Objective-c 線程系列一 atomic是安全的嗎
Objective-c 線程系列二 @synchronized
Objective-c 線程系列三 NSRecursiveLock
一 Property聲明是atomic
1 簡(jiǎn)單的將property分為值類型和對(duì)象類型催植,值類型是指primitive type,包括int,long,bool等非對(duì)象類型博其,另一種是對(duì)象類型,聲明為指針闸衫,可以指向某個(gè)符合類型定義的內(nèi)存區(qū)域排作。
2 討論多線程安全的時(shí)候泡挺,其實(shí)是在討論多個(gè)線程同時(shí)訪問(wèn)一個(gè)內(nèi)存區(qū)域的安全問(wèn)題渐裸。針對(duì)同一塊區(qū)域,有讀和寫(xiě)的兩種操作仍劈,讀和寫(xiě)同時(shí)發(fā)生在同一塊區(qū)域的時(shí)候厕倍,就有可能出現(xiàn)多線程不安全。
3 我們只有一個(gè)地址總線贩疙,一個(gè)內(nèi)存讹弯。即使在多線程的環(huán)境下,也不可能存在兩個(gè)線程同時(shí)訪問(wèn)同一塊內(nèi)存區(qū)域的場(chǎng)景这溅,內(nèi)存的訪問(wèn)一定是通過(guò)一個(gè)地址總線串行排隊(duì)訪問(wèn)的组民。所以,內(nèi)存的訪問(wèn)是串行的芍躏,并不會(huì)導(dǎo)致內(nèi)存數(shù)據(jù)的錯(cuò)亂或者應(yīng)用的crash邪乍。
4 如果讀寫(xiě)的內(nèi)存長(zhǎng)度小于等于地址總線的長(zhǎng)度,那么讀寫(xiě)的操作是原子的,一次完成庇楞。比如bool,int,long在64位操作系統(tǒng)下的單次讀寫(xiě)都是原子操作榜配。所以,從訪問(wèn)內(nèi)存的角度看nonatomic和atomic沒(méi)有區(qū)別吕晌。
二 atomic的作用到底是什么蛋褥?
生成原子操作的getter和setter
設(shè)置atomic之后,默認(rèn)生成的getter和setter方法執(zhí)行時(shí)是原子的睛驳。也就是說(shuō)烙心,當(dāng)我們?cè)诰€程A執(zhí)行g(shù)etter方法的時(shí)候(創(chuàng)建調(diào)用棧,返回地址乏沸,出棧)淫茵,線程B如果想執(zhí)行setter方法,必須先等getter方法完成才能執(zhí)行蹬跃。舉個(gè)例子匙瘪,在32位系統(tǒng)里,如果通過(guò)getter返回64位的double,地址總線寬度為32位蝶缀,從內(nèi)存當(dāng)中讀取double的時(shí)候無(wú)法通過(guò)原子操作完成丹喻,如果不通過(guò)atomic加鎖,有可能會(huì)在讀取的中途在其他線程發(fā)生setter操作翁都,從而出現(xiàn)異常值碍论。如果出現(xiàn)這種異常值,就發(fā)生了多線程不安全柄慰。
三 是不是使用了atomic就一定多線程安全呢鳍悠?
不一定
atomic 只是給getter和setter加了個(gè)鎖,atomic只能保證代碼進(jìn)入getter或者setter函數(shù)內(nèi)部是安全的先煎,一旦出了getter和setter贼涩,多線程的安全只能靠程序員自己保障了巧涧。atomic由于加鎖也會(huì)帶來(lái)一些性能損耗薯蝎,所以我們?cè)诰帉?xiě)iOS代碼的時(shí)候,一般聲明property為nonatomic,自己去加鎖做同步谤绳。
四 使用了atomic線程不安全的例子
@property (atomic,strong) NSArray *array;
- (void)testAtomic{
dispatch_queue_t oneQueue = dispatch_queue_create("11", DISPATCH_QUEUE_CONCURRENT);;
dispatch_async(oneQueue, ^{
for (int i = 0; i < 1000000; i++) {
if (i%2 == 0) {
self.array = @[@"3",@"3",@"444"];
}else{
self.array = @[@"4"];
}
}
});
dispatch_queue_t secondQueue = dispatch_queue_create("22", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(secondQueue, ^{
for (int i = 0; i < 1000000; i++) {
if (self.array.count > 2) {
NSNumber *str = [self.array objectAtIndex:1];
NSLog(@"str %@",str);
}
}
});
}
五 如何做到多線程安全問(wèn)題
做到代碼串行的執(zhí)行占锯,能保證代碼執(zhí)行到一半的時(shí)候,不會(huì)有另一個(gè)線程介入缩筛,就能做到多線程安全問(wèn)題消略。這時(shí)我們可以使用加鎖的方式,來(lái)保證代碼的串行瞎抛。
在做多線程安全的時(shí)候艺演,并不是通過(guò)property加atomic關(guān)鍵字來(lái)保證安全,而是將property聲明為nonatomic(nonatomic沒(méi)有g(shù)etter,setter的鎖開(kāi)銷),然后自己加鎖胎撤。
參考文檔
蘋(píng)果開(kāi)發(fā)者文檔
細(xì)說(shuō)@synchronized和dispatch_once
正確使用多線程同步鎖@synchronized()
runtime源碼
objc-sync.mm源碼