iOS中的鎖

使用NSLock實現的鎖

? ? ? ?NSLock是Cocoa提供給我們最基本的鎖對象,這也是我們經常所使用的,除lock和unlock方法外,NSLock還提供了tryLock和lockBeforeDate:兩個方法,前一個方法會嘗試加鎖,如果鎖不可用(已經被鎖住),剛并不會阻塞線程,并返回NO。lockBeforeDate:方法會在所指定Date之前嘗試加鎖,如果在指定時間之前都不能加鎖,則返回NO。


NSLock.png

使用synchronized關鍵字構建的鎖

? ? ? ?@synchronized指令使用的obj為該鎖的唯一標識,只有當標識相同時,才為滿足互斥,如果線程2中的@synchronized(obj)改為@synchronized(other),剛線程2就不會被阻塞,@synchronized指令實現鎖的優點就是我們不需要在代碼中顯式的創建鎖對象,便可以實現鎖的機制,但作為一種預防措施,@synchronized塊會隱式的添加一個異常處理例程來保護代碼,該處理例程會在異常拋出的時候自動的釋放互斥鎖。所以如果不想讓隱式的異常處理例程帶來額外的開銷,你可以考慮使用鎖對象。

synchronized.png

使用GCD來實現的”鎖”

? ? ? ? 以上代碼構建多線程我們就已經用到了GCD的dispatch_async方法,其實在GCD中也已經提供了一種信號機制,使用它我們也可以來構建一把”鎖”(從本質意義上講,信號量與鎖是有區別,具體差異參加信號量與互斥鎖之間的區別):


Semaphore.png

NSRecursiveLock遞歸鎖

? ? ? ? NSRecursiveLock實際上定義的是一個遞歸鎖,這個鎖可以被同一線程多次請求,而不會引起死鎖。這主要是用在循環或遞歸操作中。我們先來看一個示例:

死鎖.png

? ? ? ? 這段代碼是一個典型的死鎖情況。在我們的線程中,RecursiveMethod是遞歸調用的。所以每次進入這個block時,都會去加一次鎖,而從第二次開始,由于鎖已經被使用了且沒有解鎖,所以它需要等待鎖被解除,這樣就導致了死鎖,線程被阻塞住了。調試器中會輸出如下信息:

value = 5

***?-[NSLock?lock]:?deadlock?('(null)')???***?Break?on?_NSLockError()?to?debug.

? ? ? ? 在這種情況下,我們就可以使用NSRecursiveLock。它可以允許同一線程多次加鎖,而不會造成死鎖。遞歸鎖會跟蹤它被lock的次數。每次成功的lock都必須平衡調用unlock操作。只有所有達到這種平衡,鎖最后才能被釋放,以供其它線程使用

NSConditionLock條件鎖

? ? ? ? 當我們在使用多線程的時候,有時一把只會lock和unlock的鎖未必就能完全滿足我們的使用。因為普通的鎖只能關心鎖與不鎖,而不在乎用什么鑰匙才能開鎖,而我們在處理資源共享的時候,多數情況是只有滿足一定條件的情況下才能打開這把鎖:

條件鎖.png

? ? ? ?在線程1中的加鎖使用了lock,所以是不需要條件的,所以順利的就鎖住了,但在unlock的使用了一個整型的條件,它可以開啟其它線程中正在等待這把鑰匙的臨界地,而線程2則需要一把被標識為2的鑰匙,所以當線程1循環到最后一次的時候,才最終打開了線程2中的阻塞。但即便如此,NSConditionLock也跟其它的鎖一樣,是需要lock與unlock對應的,只是lock,lockWhenCondition:與unlock,unlockWithCondition:是可以隨意組合的,當然這是與你的需求相關的。

NSDistributedLock分布式鎖

? ? ? ? 以上所有的鎖都是在解決多線程之間的沖突,但如果遇上多個進程或多個程序之間需要構建互斥的情景該怎么辦呢?這個時候我們就需要使用到NSDistributedLock了,從它的類名就知道這是一個分布式的Lock,NSDistributedLock的實現是通過文件系統的,所以使用它才可以有效的實現不同進程之間的互斥,但NSDistributedLock并非繼承于NSLock,它沒有lock方法,它只實現了tryLock,unlock,breakLock,所以如果需要lock的話,你就必須自己實現一個tryLock的輪詢,下面通過代碼簡單的演示一下吧:

分布式鎖

? ? ? 先運行程序A,然后立即運行程序B,根據打印你可以清楚的發現,當程序A剛運行的時候,程序B一直處于等待中,當大概10秒過后,程序B便打印出了appB:OK的輸出,以上便實現了兩上不同程序之間的互斥。/Users/mac/Desktop/earning__是一個文件或文件夾的地址,如果該文件或文件夾不存在,那么在tryLock返回YES時,會自動創建該文件/文件夾。在結束的時候該文件/文件夾會被清除,所以在選擇的該路徑的時候,應該選擇一個不存在的路徑,以防止誤刪了文件。

? ? ? ? 這是用在多進程之間共享資源的鎖,對 iOS 來說暫時沒用處。

參考文獻

1.www.tanhao.me/pieces/616.html/

2.justinyan.me/post/1609

3.www.tanhao.me/pieces/643.html/

4.www.tanhao.me/pieces/1731.html/

5.iOS 鎖

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 鎖是一種同步機制,用于多線程環境中對資源訪問的限制iOS中常見鎖的性能對比圖(摘自:ibireme): iOS鎖的...
    LiLS閱讀 1,553評論 0 6
  • 在平時的開發中經常使用到多線程,在使用多線程的過程中,難免會遇到資源競爭的問題,那我們怎么來避免出現這種問題那? ...
    IAMCJ閱讀 3,125評論 2 25
  • 拋磚引玉 說到鎖不得不提線程安全,說到線程安全,作為iOS程序員又不得不提 nonatomic 與 atomic ...
    Inlight先森閱讀 2,075評論 0 23
  • 在多線程操作過程中,往往一個數據同時被多個線程讀寫,在這種情況下,如果沒有相應的機制對數據進行保護,就很可能會發...
    沒技術的BUG開發攻城獅閱讀 393評論 0 0
  • 本文不介紹各種鎖的高級用法,只是整理鎖相關的知識點,幫助理解。 鎖的作用 防止在多線程(多任務)的情況下對共享資源...
    HelloiWorld閱讀 2,923評論 0 8