iOS 中的各種鎖

在日常開發(fā)過程中账蓉,為了提升程序運行效率,以及用戶體驗逾一,我們經(jīng)常使用多線程铸本。在使用多線程的過程中,難免會遇到資源競爭問題遵堵。我們采用鎖的機(jī)制來確保線程安全箱玷。

線程安全

當(dāng)一個線程訪問數(shù)據(jù)的時候,其他的線程不能對其進(jìn)行訪問鄙早,直到該線程訪問完畢汪茧。即,同一時刻限番,對同一個數(shù)據(jù)操作的線程只有一個。只有確保了這樣呀舔,才能使數(shù)據(jù)不會被其他線程污染弥虐。而線程不安全,則是在同一時刻可以有多個線程對該數(shù)據(jù)進(jìn)行訪問媚赖,從而得不到預(yù)期的結(jié)果霜瘪。

比如寫文件和讀文件,當(dāng)一個線程在寫文件的時候惧磺,理論上來說颖对,如果這個時候另一個線程來直接讀取的話,那么得到將是不可預(yù)期的結(jié)果磨隘。

為了線程安全缤底,我們可以使用鎖的機(jī)制來確保,同一時刻只有同一個線程來對同一個數(shù)據(jù)源進(jìn)行訪問番捂。在開發(fā)過程中我們通常使用以下幾種鎖个唧。

NSLock

NSRecursiveLock

NSCondition

NSConditionLock

pthread_mutex

pthread_rwlock

POSIX Conditions

OSSpinLock

os_unfair_lock

dispatch_semaphore

@synchronized

信號量

在多線程環(huán)境下用來確保代碼不會被并發(fā)調(diào)用。在進(jìn)入一段代碼前设预,必須獲得一個信號量徙歼,在結(jié)束代碼前,必須釋放該信號量鳖枕,其他想要想要執(zhí)行該代碼的線程必須等待直到前者釋放了該信號量魄梯。

以一個停車場的運作為例。簡單起見宾符,假設(shè)停車場只有三個車位酿秸,一開始三個車位都是空的。這時如果同時來了五輛車吸奴,看門人允許其中三輛直接進(jìn)入允扇,然后放下車攔缠局,剩下的車則必須在入口等待,此后來的車也都不得不在入口處等待考润。這時狭园,有一輛車離開停車場,看門人得知后糊治,打開車攔唱矛,放入外面的一輛進(jìn)去,如果又離開兩輛井辜,則又可以放入兩輛绎谦,如此往復(fù)。

在這個停車場系統(tǒng)中粥脚,車位是公共資源窃肠,每輛車好比一個線程,看門人起的就是信號量的作用刷允。

互斥鎖

一種用來防止多個線程同一時刻對共享資源進(jìn)行訪問的信號量冤留,它的原子性確保了如果一個線程鎖定了一個互斥量,將沒有其他線程在同一時間可以鎖定這個互斥量树灶。它的唯一性確保了只有它解鎖了這個互斥量纤怒,其他線程才可以對其進(jìn)行鎖定。當(dāng)一個線程鎖定一個資源的時候天通,其他對該資源進(jìn)行訪問的線程將會被掛起泊窘,直到該線程解鎖了互斥量,其他線程才會被喚醒像寒,進(jìn)一步才能鎖定該資源進(jìn)行操作烘豹。

優(yōu)點:能有效防止因多線程搶奪資源造成的數(shù)據(jù)安全問題;

缺點:需要消耗大量的CPU資源萝映;

NSLock

NSLock實現(xiàn)了最基本的互斥鎖吴叶,遵循了 NSLocking 協(xié)議,通過 lock 和 unlock 來進(jìn)行鎖定和解鎖序臂。其使用也非常簡單

由于是互斥鎖蚌卤,當(dāng)一個線程進(jìn)行訪問的時候,該線程獲得鎖奥秆,其他線程進(jìn)行訪問的時候逊彭,將被操作系統(tǒng)掛起,直到該線程釋放鎖构订,其他線程才能對其進(jìn)行訪問侮叮,從而卻確保了線程安全。但是如果連續(xù)鎖定兩次悼瘾,則會造成死鎖問題囊榜。那如果想在遞歸中使用鎖审胸,那要怎么辦呢,這就用到了 NSRecursiveLock 遞歸鎖卸勺。

NSRecursiveLock

遞歸鎖砂沛,顧名思義,可以被一個線程多次獲得曙求,而不會引起死鎖碍庵。它記錄了成功獲得鎖的次數(shù),每一次成功的獲得鎖悟狱,必須有一個配套的釋放鎖和其對應(yīng)静浴,這樣才不會引起死鎖。只有當(dāng)所有的鎖被釋放之后挤渐,其他線程才可以獲得鎖

NSCondition

NSCondition 是一種特殊類型的鎖苹享,通過它可以實現(xiàn)不同線程的調(diào)度。一個線程被某一個條件所阻塞挣菲,直到另一個線程滿足該條件從而發(fā)送信號給該線程使得該線程可以正確的執(zhí)行富稻。比如說,你可以開啟一個線程下載圖片白胀,一個線程處理圖片。這樣的話抚岗,需要處理圖片的線程由于沒有圖片會阻塞或杠,當(dāng)下載線程下載完成之后,則滿足了需要處理圖片的線程的需求宣蔚,這樣可以給定一個信號向抢,讓處理圖片的線程恢復(fù)運行。

NSConditionLock

NSConditionLock 對象所定義的互斥鎖可以在使得在某個條件下進(jìn)行鎖定和解鎖胚委。它和 NSCondition 很像挟鸠,但實現(xiàn)方式是不同的。

當(dāng)兩個線程需要特定順序執(zhí)行的時候亩冬,例如生產(chǎn)者消費者模型艘希,則可以使用 NSConditionLock 。當(dāng)生產(chǎn)者執(zhí)行執(zhí)行的時候硅急,消費者可以通過特定的條件獲得鎖覆享,當(dāng)生產(chǎn)者完成執(zhí)行的時候,它將解鎖該鎖营袜,然后把鎖的條件設(shè)置成喚醒消費者線程的條件撒顿。鎖定和解鎖的調(diào)用可以隨意組合,lock 和 unlockWithCondition: 配合使用 lockWhenCondition: 和 unlock 配合使用荚板。

當(dāng)生產(chǎn)者釋放鎖的時候凤壁,把條件設(shè)置成了1吩屹。這樣消費者可以獲得該鎖,進(jìn)而執(zhí)行程序拧抖,如果消費者獲得鎖的條件和生產(chǎn)者釋放鎖時給定的條件不一致煤搜,則消費者永遠(yuǎn)無法獲得鎖,也不能執(zhí)行程序徙鱼。同樣宅楞,如果消費者釋放鎖給定的條件和生產(chǎn)者獲得鎖給定的條件不一致的話,則生產(chǎn)者也無法獲得鎖袱吆,程序也不能執(zhí)行厌衙。

pthread_mutex

POSIX 互斥鎖是一種超級易用的互斥鎖,使用的時候绞绒,只需要初始化一個 pthread_mutex_t 用 pthread_mutex_lock 來鎖定 pthread_mutex_unlock 來解鎖婶希,當(dāng)使用完成后,記得調(diào)用 pthread_mutex_destroy 來銷毀鎖蓬衡。

pthread_rwlock

讀寫鎖喻杈,在對文件進(jìn)行操作的時候,寫操作是排他的狰晚,一旦有多個線程對同一個文件進(jìn)行寫操作筒饰,后果不可估量,但讀是可以的壁晒,多個線程讀取時沒有問題的瓷们。

當(dāng)讀寫鎖被一個線程以讀模式占用的時候,寫操作的其他線程會被阻塞秒咐,讀操作的其他線程還可以繼續(xù)進(jìn)行谬晕。

當(dāng)讀寫鎖被一個線程以寫模式占用的時候,寫操作的其他線程會被阻塞携取,讀操作的其他線程也被阻塞攒钳。

POSIX Conditions

POSIX 條件鎖需要互斥鎖和條件兩項來實現(xiàn),雖然看起來沒什么關(guān)系雷滋,但在運行時中不撑,互斥鎖將會與條件結(jié)合起來。線程將被一個互斥和條件結(jié)合的信號來喚醒惊豺。

首先初始化條件和互斥鎖燎孟,當(dāng) ready_to_go 為 flase 的時候,進(jìn)入循環(huán)尸昧,然后線程將會被掛起揩页,直到另一個線程將 ready_to_go 設(shè)置為 true 的時候,并且發(fā)送信號的時候,該線程會才被喚醒爆侣。

OSSpinLock

自旋鎖萍程,和互斥鎖類似,都是為了保證線程安全的鎖兔仰。但二者的區(qū)別是不一樣的茫负,對于互斥鎖,當(dāng)一個線程獲得這個鎖之后乎赴,其他想要獲得此鎖的線程將會被阻塞忍法,直到該鎖被釋放。但自選鎖不一樣榕吼,當(dāng)一個線程獲得鎖之后饿序,其他線程將會一直循環(huán)在哪里查看是否該鎖被釋放。所以羹蚣,此鎖比較適用于鎖的持有者保存時間較短的情況下原探。

然而,YYKit 作者 @ibireme 的文章也有說這個自旋鎖存在優(yōu)先級反轉(zhuǎn)問題顽素,具體文章可以戳 不再安全的 OSSpinLock咽弦。

os_unfair_lock

自旋鎖已經(jīng)不在安全,然后蘋果又整出來個 os_unfair_lock_t (╯‵□′)╯︵┻━┻

這個鎖解決了優(yōu)先級反轉(zhuǎn)問題胁出。

@synchronized

一個便捷的創(chuàng)建互斥鎖的方式型型,它做了其他互斥鎖所做的所有的事情。

如果你在不同的線程中傳過去的是一樣的標(biāo)識符全蝶,先獲得鎖的會鎖定代碼塊输莺,另一個線程將被阻塞,如果傳遞的是不同的標(biāo)識符裸诽,則不會造成線程阻塞。

總結(jié)

應(yīng)當(dāng)針對不同的操作使用不同的鎖型凳,而不能一概而論那種鎖的加鎖解鎖速度快丈冬。

當(dāng)進(jìn)行文件讀寫的時候,使用 pthread_rwlock 較好甘畅,文件讀寫通常會消耗大量資源埂蕊,而使用互斥鎖同時讀文件的時候會阻塞其他讀文件線程,而 pthread_rwlock 不會疏唾。

當(dāng)性能要求較高時候蓄氧,可以使用 pthread_mutex 或者 dispath_semaphore,由于 OSSpinLock 不能很好的保證線程安全槐脏,而在只有在 iOS10 中才有 os_unfair_lock 喉童,所以,前兩個是比較好的選擇顿天。既可以保證速度堂氯,又可以保證線程安全蔑担。

對于 NSLock 及其子類,速度來說 NSLock < NSCondition < NSRecursiveLock < NSConditionLock 咽白。


- (void)viewDidLoad

{

? ? ? ? ? [super viewDidLoad];

? ? ? ? ? NSLog(@"1");

? ? ? ? ? dispatch_sync(dispatch_get_main_queue(), ^{

? ? ? ? ? ? ? ? ? ?NSLog(@"2");

? ? ? ? ? });

? ? ? ? ? NSLog(@"3");

} ? ?輸出 1 后 會造成死鎖啤握。

原因? dispatch_sync? 是同步線程執(zhí)行代碼 要阻塞當(dāng)前線程,如果當(dāng)前線程是主線程晶框,首先被阻塞排抬,然后執(zhí)行輸出,問題是代碼的參數(shù)是dispatch_get_main_queue() 它會獲取主線程然后在主線程執(zhí)行輸出 主線程本來就被阻塞 所以造成了互鎖授段。(如果當(dāng)前調(diào)用dispatch_sync的是主隊列的話會死鎖蹲蒲,否則不會。因為dispatch_sync會阻塞當(dāng)前線程等待block執(zhí)行完畢然后返回畴蒲,但是當(dāng)前的block加入到了當(dāng)前的隊列等待dispatch_sync的執(zhí)行完畢悠鞍,那么這么互相依賴顯然死鎖)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市模燥,隨后出現(xiàn)的幾起案子咖祭,更是在濱河造成了極大的恐慌,老刑警劉巖蔫骂,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件么翰,死亡現(xiàn)場離奇詭異,居然都是意外死亡辽旋,警方通過查閱死者的電腦和手機(jī)浩嫌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來补胚,“玉大人码耐,你說我怎么就攤上這事∪芷洌” “怎么了骚腥?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵,是天一觀的道長瓶逃。 經(jīng)常有香客問我束铭,道長,這世上最難降的妖魔是什么厢绝? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任契沫,我火速辦了婚禮,結(jié)果婚禮上昔汉,老公的妹妹穿的比我還像新娘懈万。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布钞速。 她就那樣靜靜地躺著贷掖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪渴语。 梳的紋絲不亂的頭發(fā)上苹威,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天,我揣著相機(jī)與錄音驾凶,去河邊找鬼牙甫。 笑死,一個胖子當(dāng)著我的面吹牛调违,可吹牛的內(nèi)容都是我干的窟哺。 我是一名探鬼主播,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼技肩,長吁一口氣:“原來是場噩夢啊……” “哼且轨!你這毒婦竟也來了题翻?” 一聲冷哼從身側(cè)響起禁荒,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤弓叛,失蹤者是張志新(化名)和其女友劉穎揩晴,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體唉匾,經(jīng)...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡讥蔽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年析恋,在試婚紗的時候發(fā)現(xiàn)自己被綠了剧浸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锹引。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖唆香,靈堂內(nèi)的尸體忽然破棺而出嫌变,到底是詐尸還是另有隱情,我是刑警寧澤躬它,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布初澎,位于F島的核電站,受9級特大地震影響虑凛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜软啼,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一桑谍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧祸挪,春花似錦锣披、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽增热。三九已至,卻和暖如春胧辽,著一層夾襖步出監(jiān)牢的瞬間峻仇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工邑商, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留摄咆,地道東北人。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓人断,卻偏偏與公主長得像吭从,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子恶迈,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,926評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 在日常開發(fā)過程中涩金,為了提升程序運行效率,以及用戶體驗暇仲,我們經(jīng)常使用多線程步做。在使用多線程的過程中,難免會遇到資源競爭...
    xiao333ma閱讀 1,937評論 1 2
  • 在日常開發(fā)過程中熔吗,為了提升程序運行效率辆床,以及用戶體驗,我們經(jīng)常使用多線程桅狠。在使用多線程的過程中讼载,難免會遇到資源競爭...
    知識小集閱讀 5,728評論 8 61
  • 鎖是一種同步機(jī)制,用于多線程環(huán)境中對資源訪問的限制iOS中常見鎖的性能對比圖(摘自:ibireme): iOS鎖的...
    LiLS閱讀 1,524評論 0 6
  • 《湖邊兇殺案》這部作品的名字不能再直白了中跌,地點:湖邊咨堤,事件:兇殺案。往往是推理小說家處心積慮的盡量拖延讀者接觸核心...
    九月城池閱讀 1,148評論 1 1
  • 召喚師峽谷啊漩符, 我想問問你一喘, 你到底有什么風(fēng)景? 讓我那么癡迷你的美麗嗜暴。 召喚師峽谷啊凸克, 我想問問你。 為何每天都...
    小幸運小開心閱讀 354評論 4 0