iOS中atomic修飾符的底層實現


在iOS中,atomic表示一個類的屬性getter/setter具有原子性。那么iOS底層是如何保證這種原子性的呢?

我們有一個類A,它有一個屬性X具有atomic:

@property (atomic, strong) X *x;

當我們為這個這個X屬性賦值的時候:-[A setX:]的匯編代碼如下:

 1 0x10e320f00 <+0>:  push   rbp
 2     0x10e320f01 <+1>:  mov    rbp, rsp
 3     0x10e320f04 <+4>:  sub    rsp, 0x20
 4     0x10e320f08 <+8>:  mov    qword ptr [rbp - 0x8], rdi
 5     0x10e320f0c <+12>: mov    qword ptr [rbp - 0x10], rsi
 6     0x10e320f10 <+16>: mov    qword ptr [rbp - 0x18], rdx
 7     0x10e320f14 <+20>: mov    rsi, qword ptr [rbp - 0x10]
 8     0x10e320f18 <+24>: mov    rax, qword ptr [rbp - 0x8]
 9     0x10e320f1c <+28>: mov    rcx, qword ptr [rbp - 0x18]
10     0x10e320f20 <+32>: mov    rdi, rax
11     0x10e320f23 <+35>: mov    rdx, rcx
12     0x10e320f26 <+38>: mov    ecx, 0x18
13     0x10e320f2b <+43>: call   0x10e321312               ; symbol stub for: objc_setProperty_atomic 注意這行
14     0x10e320f30 <+48>: add    rsp, 0x20
15     0x10e320f34 <+52>: pop    rbp
16     0x10e320f35 <+53>: ret    

上面的匯編代碼第13行顯示,setX里面調用了objc rumtime函數objc_setProperty_atomic函數。打開objc_setProperty_atomic源碼:

void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
    reallySetProperty(self, _cmd, newValue, offset, true, false, false);
}
 1 static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
 2 {
 3     if (offset == 0) {
 4         object_setClass(self, newValue);
 5         return;
 6     }
 7 
 8     id oldValue;
 9     id *slot = (id*) ((char*)self + offset);
10 
11     if (copy) {
12         newValue = [newValue copyWithZone:NULL];
13     } else if (mutableCopy) {
14         newValue = [newValue mutableCopyWithZone:NULL];
15     } else {
16         if (*slot == newValue) return;
17         newValue = objc_retain(newValue);
18     }
19 
20     if (!atomic) {
21         oldValue = *slot;
22         *slot = newValue;
23     } else { //如果是atomic屬性修飾,會加上自旋鎖
24         spin_lock_t *slotlock = &PropertyLocks[GOODHASH(slot)];
25         _spin_lock(slotlock);
26         oldValue = *slot;
27         *slot = newValue;        
28         _spin_unlock(slotlock);
29     }
30 
31     objc_release(oldValue);
32 }

通過源碼發現,objc_setProperty_atomic函數調用了reallySetProperty函數,而reallySetProperty函數的23行,如果是atomic屬性修飾的,為這個變量賦值會加上自旋鎖。

 

下面我們看下訪問X這個變量時的getter方法:-[A x],匯編代碼如下:

 1 ->  0x10c09fed0 <+0>:  push   rbp
 2     0x10c09fed1 <+1>:  mov    rbp, rsp
 3     0x10c09fed4 <+4>:  mov    qword ptr [rbp - 0x8], rdi
 4     0x10c09fed8 <+8>:  mov    qword ptr [rbp - 0x10], rsi
 5     0x10c09fedc <+12>: mov    rsi, qword ptr [rbp - 0x10]
 6     0x10c09fee0 <+16>: mov    rdi, qword ptr [rbp - 0x8]
 7     0x10c09fee4 <+20>: mov    edx, 0x18
 8     0x10c09fee9 <+25>: mov    ecx, 0x1
 9     0x10c09feee <+30>: pop    rbp
10     0x10c09feef <+31>: jmp    0x10c0a02fa               ; symbol stub for: objc_getProperty 寄存器ecx為1,表示傳遞給objc_getProperty的第4個參數為YES,而這個參數剛好表示是否是atomic的

上面匯編代碼第10行,getter方法訪問了objc運行時的objc_getProperty方法,我們查看源碼:

1 id 
2 objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) 
3 {
4     return objc_getProperty_non_gc(self, _cmd, offset, atomic);
5 }
 1 id objc_getProperty_non_gc(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
 2     if (offset == 0) {
 3         return object_getClass(self);
 4     }
 5 
 6     // Retain release world
 7     id *slot = (id*) ((char*)self + offset);
 8     if (!atomic) return *slot;
 9         
10     // Atomic retain release world    
11     // Atomic屬性訪問會加鎖
12     spin_lock_t *slotlock = &PropertyLocks[GOODHASH(slot)];
13     _spin_lock(slotlock);
14     id value = objc_retain(*slot);
15     _spin_unlock(slotlock);
16     
17     // for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
18     return objc_autoreleaseReturnValue(value);
19 }

從上面getter方法匯編碼可以知道傳遞給objc_getProperty第四個參數為YES,也就是atomic參數為YES。而objc_getProperty調用了objc_getProperty_non_gc函數,這個函數里面第12行,如果是atomic屬性,訪問的時候會加鎖。

 

測試的時候發現,如果atomic修飾的是諸如整型這些簡單類型的變量,setter/getter時都是使用對象首地址+偏移量完成,而不會調用objc_getProperty函數和objc_setProperty_atomic函數。可能是因為對這些變量的操作,本身就是原子性的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM