iOS中常見鎖

pthread_mutex

POSIX threads(簡稱Pthreads)定義了一套跨平臺的多線程常用API,線程同步在并行編程中非常重要的,其中最典型的應(yīng)用就是用Pthreads提供的鎖機(jī)制來對多個線程之間共享臨界區(qū)進(jìn)行保護(hù)。

Pthreads鎖的常見用法;

pthread_mutexattr_t attr;  
pthread_mutexattr_init(&attr);  //初始化屬性
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);  // 定義鎖的屬性,定義成常規(guī)鎖
pthread_mutex_t mutex;  
pthread_mutex_init(&mutex, &attr) // 創(chuàng)建鎖
pthread_mutex_lock(&mutex); // 申請鎖  
    // 臨界區(qū)代碼
pthread_mutex_unlock(&mutex); // 釋放鎖 

從上面的代碼中我們很容易就明白其用法這里不在詳述,我們下面著重對鎖的類型進(jìn)行介紹。在方法pthread_mutexattr_settype中,我們將第二個參數(shù)設(shè)置為PTHREAD_MUTEX_NORMAL,這是將鎖設(shè)置為普通鎖,不做死鎖檢測。有可能造成死鎖,實際上它還可以有其他幾種類型。

  1. PTHREAD_MUTEX_NORMAL
    如果mutex的type被置為PTHREAD_MUTEX_NORMAL,則系統(tǒng)將不會為他提供死鎖檢測,嘗試對已經(jīng)加鎖的mutex進(jìn)行加鎖操作的時候,將會造成死鎖。如果一個線程試圖解鎖一個還沒有加鎖或者已經(jīng)被解鎖的mutex進(jìn)行解鎖操作的時候,會發(fā)生不可預(yù)測問題。
  2. PTHREAD_MUTEX_ERRORCHECK
    如果mutex的type被置為PTHREAD_MUTEX_ERRORCHECK,則系統(tǒng)將會為他提供錯誤檢測。嘗試對已經(jīng)加鎖的mutex進(jìn)行加鎖操作的時候會返回錯誤。如果一個線程試圖解鎖一個還沒有加鎖或者已經(jīng)被解鎖的mutex進(jìn)行解鎖操作的時候,也會返回錯誤。
  3. PTHREAD_MUTEX_RECURSIVE(遞歸鎖)
    如果mutex的type被置為PTHREAD_MUTEX_RECURSIVE,mutex會維護(hù)一個加鎖次數(shù)的變量。當(dāng)一個線程第一次成功給mutex加鎖后,加鎖次數(shù)將被設(shè)置為1.線程每次對mutex加鎖,加鎖次數(shù)加1,每次解鎖加鎖次數(shù)減1,當(dāng)加鎖次數(shù)變?yōu)?時,其他線程就可以對mutex加鎖了。如果一個線程試圖解鎖一個還沒有加鎖或者已經(jīng)被解鎖的mutex進(jìn)行解鎖操作的時候,會返回錯誤。
  4. PTHREAD_MUTEX_DEFAULT
    如果mutex的type被置為PTHREAD_MUTEX_DEFAULT,嘗試遞歸的給mutex加鎖會導(dǎo)致不可預(yù)知的錯誤,如果一個線程試圖解鎖一個還沒有加鎖或者已經(jīng)被解鎖的mutex進(jìn)行解鎖操作的時候也會返回不可預(yù)知的錯誤。

其中PTHREAD_MUTEX_NORMAL,PTHREAD_MUTEX_ERRORCHECK,PTHREAD_MUTEX_DEFAULT定義的是互斥鎖,PTHREAD_MUTEX_RECURSIVE定義的是遞歸鎖。

一般情況下,一個線程只能申請一次鎖,也只能在獲得鎖的情況下才能釋放鎖,多次申請鎖或釋放未獲得的鎖都會導(dǎo)致不可預(yù)知錯誤。假設(shè)在已經(jīng)獲得鎖的情況下再次申請鎖,線程會因為等待鎖的釋放而進(jìn)入睡眠狀態(tài),因此就不可能再釋放鎖,從而導(dǎo)致死鎖。

然而這種情況經(jīng)常會發(fā)生,比如某個函數(shù)申請了鎖,在臨界區(qū)內(nèi)又遞歸調(diào)用了自己,遞歸鎖就可以解決這種問題。遞歸鎖的簡單實現(xiàn)可以看這里

自旋鎖

自旋鎖與互斥鎖有點(diǎn)類似,只是自旋鎖不會引起調(diào)用者睡眠,如果自旋鎖已經(jīng)被別的執(zhí)行單元保持,調(diào)用者就一直循環(huán)在那里看是否該自旋鎖的保持者已經(jīng)釋放了鎖,"自旋"一詞就是因此而得名。

從實現(xiàn)原理上來講,Mutex屬于sleep-waiting類型的鎖。例如在一個雙核的機(jī)器上有兩個線程(線程A和線程B),它們分別運(yùn)行在Core0和 Core1上。假設(shè)線程A想要通過
pthread_mutex_lock操作去得到一個臨界區(qū)的鎖,而此時這個鎖正被線程B所持有,那么線程A就會被阻塞(blocking),Core0會在此時進(jìn)行上下文切換(Context Switch)將線程A置于
等待隊列中,此時Core0就可以運(yùn)行其他的任務(wù)(例如另一個線程C)而不必進(jìn)行忙等待。而Spin lock則不然,它屬于busy-waiting類型的鎖,如果線程A是使用pthread_spin_lock操作去請求鎖,那么線程A就會一直在Core0上進(jìn)行忙等待并不停的進(jìn)行鎖請求,直到得到這個鎖為止。

因為自旋鎖不會引起調(diào)用者睡眠,所以自旋鎖的效率遠(yuǎn)高于互斥鎖。雖然它的效率比互斥鎖高,但是它也有些不足之處,自旋鎖一直占用CPU,他在未獲得鎖的情況下,一直運(yùn)行--自旋,所以占用著CPU,如果不能在很短的時間內(nèi)獲得鎖,這無疑會使CPU效率降低。

自旋鎖的簡單實現(xiàn)邏輯可以查看這里

自旋鎖

參考資料:
1.https://bestswifter.com/ios-lock/
2.https://www.cnblogs.com/zendu/p/5387596.html
3.http://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_mutex_lock.html
4.http://blog.sina.com.cn/s/blog_7c6086150101a30y.html

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

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

  • 鎖是一種同步機(jī)制,用于多線程環(huán)境中對資源訪問的限制iOS中常見鎖的性能對比圖(摘自:ibireme): iOS鎖的...
    LiLS閱讀 1,627評論 0 6
  • 轉(zhuǎn)自(https://bestswifter.com/ios-lock/#) 深入理解 iOS 開發(fā)中的鎖 摘要 ...
    犯色戒的和尚閱讀 378評論 0 1
  • 在平時的開發(fā)中經(jīng)常使用到多線程,在使用多線程的過程中,難免會遇到資源競爭的問題,那我們怎么來避免出現(xiàn)這種問題那? ...
    IAMCJ閱讀 3,329評論 2 25
  • 線程安全是怎么產(chǎn)生的 常見比如線程內(nèi)操作了一個線程外的非線程安全變量,這個時候一定要考慮線程安全和同步。 - (v...
    幽城88閱讀 772評論 0 0
  • 對很多人來說,兩點(diǎn)一線便是生活的全部。 曩時,上班狗們排隊擠上公交車,我總是試圖穿越擁擠的人墻,贏得一個靠窗的景觀...
    趙忘川閱讀 195評論 0 0

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