iOS 線程安全之@synchronized同步鎖

//  先看問(wèn)題
- (NSString *)xua {
    if (!_xua) {
        @synchronized (_xua) {
            if (!_xua) {
                _xua = [TAFManager XUA];
            }
        }
    }
    return _xua;
}

這段代碼有什么問(wèn)題嗎?為了保持線程同步,需要給對(duì)象加鎖。對(duì)@synchronized: 防止不同的線程同時(shí)執(zhí)行同一段代碼。

結(jié)果

上面的線程會(huì)存在_xuanil的情況(第一次獲取值的時(shí)候),當(dāng)被鎖定的對(duì)象為nil時(shí),其實(shí)@synchronized是無(wú)作用的,也就是不能保證線程安全。

原理

我對(duì) @synchronized的實(shí)現(xiàn)十分好奇并搜了一些它的細(xì)節(jié)。我找到了一些答案,但這些解釋都沒(méi)有達(dá)到我想要的深度。鎖是如何與你傳入 @synchronized 的對(duì)象關(guān)聯(lián)上的?@synchronized會(huì)保持(retain,增加引用計(jì)數(shù))被鎖住的對(duì)象么?假如你傳入 @synchronized 的對(duì)象在 @synchronizedblock里面被釋放或者被賦值為 nil 將會(huì)怎么樣?這些全都是我想回答的問(wèn)題。而我這次的收獲,會(huì)要你好看。
@synchronized 的文檔告訴我們, @synchronized block 在被保護(hù)的代碼上暗中添加了一個(gè)異常處理。為的是同步某對(duì)象時(shí)如若拋出異常,鎖會(huì)被釋放掉。@synchronized block 會(huì)變成 objc_sync_enterobjc_sync_exit的成對(duì)兒調(diào)用。我們不知道這些函數(shù)是干啥的,但基于這些事實(shí)我們可以認(rèn)為編譯器將這樣的代碼:

@synchronized(obj) {
    // do work
}
轉(zhuǎn)化成這樣的東東
@try {
    objc_sync_enter(obj);
    // do work
} @finally {
    objc_sync_exit(obj);    
}

objc_sync_enter 和 objc_sync_exit 是啥?它們是如何實(shí)現(xiàn)的?在 Xcode 中按住 Command 鍵單擊它們,然后進(jìn)到了,里面有我們感興趣的這兩個(gè)函數(shù):

/** 
 * Begin synchronizing on 'obj'.  
 * Allocates recursive pthread_mutex associated with 'obj' if needed.
 * 
 * @param obj The object to begin synchronizing on.
 * 
 * @return OBJC_SYNC_SUCCESS once lock is acquired.  
 */
OBJC_EXPORT int
objc_sync_enter(id _Nonnull obj)
    OBJC_AVAILABLE(10.3, 2.0, 9.0, 1.0, 2.0);

/** 
 * End synchronizing on 'obj'. 
 * 
 * @param obj The object to end synchronizing on.
 * 
 * @return OBJC_SYNC_SUCCESS or OBJC_SYNC_NOT_OWNING_THREAD_ERROR
 */
OBJC_EXPORT int
objc_sync_exit(id _Nonnull obj)
    OBJC_AVAILABLE(10.3, 2.0, 9.0, 1.0, 2.0);

不過(guò),objc_sync_enter的文檔告訴我們一些新東西: @synchronized 結(jié)構(gòu)在工作時(shí)為傳入的對(duì)象分配了一個(gè)遞歸鎖。分配工作何時(shí)發(fā)生,如何發(fā)生呢?它怎樣處理 nil?幸運(yùn)的是 Objective-C runtime 是開(kāi)源的,所以我們可以馬上閱讀源碼并找到答案!

注:遞歸鎖在被同一線程重復(fù)獲取時(shí)不會(huì)產(chǎn)生死鎖。
想深入了解,有個(gè)叫做 NSRecursiveLock 的現(xiàn)成的類(lèi)也是這樣的,你可以試試。
你可以在這里找到 objc-sync 的全部源碼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 作者:Ryan Kaplan 譯者:徐嘉宏原文地址:More than you want to know abou...
    簞食豆羹閱讀 10,741評(píng)論 13 99
  • 在這篇文章中,我將為你整理一下 iOS 開(kāi)發(fā)中幾種多線程方案,以及其使用方法和注意事項(xiàng)。當(dāng)然也會(huì)給出幾種多線程的案...
    張戰(zhàn)威ican閱讀 692評(píng)論 0 0
  • 老覺(jué)得自個(gè)憋屈,活的怎么這么憋屈呢。
    君為下閱讀 173評(píng)論 0 0
  • 發(fā)現(xiàn)最近自己很浮躁,心情也不是很美麗,老爸老媽50歲的生日,讓我突然發(fā)現(xiàn),我不能再任性了,人活著不能只為自己考慮。...
    成長(zhǎng)中的木木閱讀 235評(píng)論 2 1
  • “現(xiàn)在我們來(lái)想象一個(gè)人物吧,她叫Maria?!蹦行訟對(duì)男性H說(shuō),“她是個(gè)女的,頭發(fā)很長(zhǎng),不過(guò)總是挽起來(lái)——??!她的...
    realnero閱讀 277評(píng)論 0 0

友情鏈接更多精彩內(nèi)容