iOS開發(fā)中常用的幾種鎖

iOS開發(fā)中常用的幾種鎖

簡介:

??操作系統(tǒng)在進行多線程調(diào)度的時候种玛,為了保證多線程安全引入了鎖的機制弦疮,以實現(xiàn)指定代碼或資源在某時間內(nèi)只可以被有限個線程訪問。這里主要介紹iOS開發(fā)中褂痰,使用Objective-C開發(fā)所用到的幾種鎖的用法念颈。


1?iOS開發(fā)中常用的幾種鎖

1.1?????? OSSpinLock 自旋鎖

1.2?????? pthread_mutex

1.3?????? pthread_mutex(recursive)

1.4?????? NSLock

1.5?????? dispatch_semaphore

1.6?????? NSCondition

1.7?????? NSRecursiveLock

1.8?????? NSConditionLock

1.9?????? @synchronized

以上為OC作iOS開發(fā)語言時常用到的鎖,其中pthread_mutex和pthread_mutex(recursive) 是C語言實現(xiàn)的卵慰,來源于遵循POSIX標準的pthread多線程庫沙郭。


2?各個鎖的特點和使用方法以及性能總結(jié)

2.1?OSSpinLock(已被棄用)

OSSpinLock 是一種自旋鎖,也只有加鎖裳朋,解鎖病线,嘗試加鎖三個方法,其中嘗試加鎖是非線程阻塞的∷吞簦可用通過 #import <libkern/OSAtomic.h> 引入并調(diào)用绑莺, 使用示例:

OSSpinLock theLock = OS_SPINLOCK_INIT;

OSSpinLockLock(&theLock);

//要執(zhí)行的代碼

OSSpinLockUnlock(&theLock);

OSSpinlock可能造成死鎖的原因:

OSSpinLock 不再安全,原因是有可能在優(yōu)先級比較低的線程里對共享資源進行加鎖了惕耕,然后高優(yōu)先級的線程搶占了低優(yōu)先級的調(diào)用CPU時間纺裁,導致高優(yōu)先級的線程一直在等待低優(yōu)先級的線程釋放鎖,然而低優(yōu)先級根本沒法搶占高優(yōu)先級的CPU時間赡突。這種情況我們稱作 優(yōu)先級倒轉(zhuǎn)对扶。

2.2?pthread_mutex??pthread_mutex(recursive)

pthread_mutex表示互斥鎖, 當鎖被占用,而其他線程申請鎖時惭缰,不是使用忙等浪南,而是阻塞線程并睡眠。將線程從睡眠狀態(tài)中喚醒也是比較耗費內(nèi)存資源

示例:

pthread_mutexattr_t attr;?

pthread_mutexattr_init(&attr);?

pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);? // 定義鎖的屬性

pthread_mutex_t mutex;?

pthread_mutex_init(&mutex, &attr) // 創(chuàng)建鎖

pthread_mutex_lock(&mutex); // 申請鎖

//線程安全區(qū)域

pthread_mutex_unlock(&mutex);?// 釋放鎖


pthread_mutex(recursive)是遞歸鎖漱受,也就是允許一個線程遞歸的申請鎖络凿,只要把 attr 的類型改成 PTHREAD_MUTEX_RECURSIVE 即可.


2.3?NSLock

NSLock是非遞歸鎖,當同一線程重復獲取同一非遞歸鎖時昂羡,就會發(fā)生死鎖

http://www.reibang.com/p/6116ec8a5595

原因如下:由于當前線程運行到第一個lock加鎖絮记,現(xiàn)在再次運行到lock同樣的鎖,需等待當前線程解鎖虐先,把當前線程掛起怨愤,不能解鎖

NSLock是非遞歸鎖,當同一線程重復獲取同一非遞歸鎖時蛹批,就會發(fā)生死鎖

解決辦法:

我們可以用NSRecursiveLock或者@synchronized替代NSLock

因為NSRecursiveLock或者@synchronized都是遞歸鎖撰洗,

遞歸鎖:它允許同一線程多次加鎖,而不會造成死鎖腐芍。

NSLock 是OC以對象的形式暴露給開發(fā)者的一種鎖差导,它的實現(xiàn)非常簡單,通過宏猪勇,定義了 lock 方法:

#define??? MLOCK \

- (void) lock\

{\

? int err = pthread_mutex_lock(&_mutex);\

? // 錯誤處理 ……

}

NSLock 只是在內(nèi)部封裝了一個 pthread_mutex设褐,屬性為 PTHREAD_MUTEX_ERRORCHECK,它會損失一定性能換來錯誤提示泣刹。

這里使用宏定義的原因是助析,OC 內(nèi)部還有其他幾種鎖,他們的 lock 方法都是一模一樣椅您,僅僅是內(nèi)部 pthread_mutex 互斥鎖的類型不同外冀。通過宏定義,可以簡化方法的定義襟沮。

NSLock 比 pthread_mutex 略慢的原因在于它需要經(jīng)過方法調(diào)用,同時由于緩存的存在,多次方法調(diào)用不會對性能產(chǎn)生太大的影響开伏。

OSSpinLock 和 NSlock的比較

NSLock 請求加鎖失敗的話膀跌,會先輪詢,但一秒過后便會使線程進入 waiting 狀態(tài)固灵,等待喚醒捅伤。而 OSSpinLock 會一直輪詢,等待時會消耗大量 CPU 資源巫玻,不適用于較長時間的任務(wù)丛忆。


2.4?dispatch_semaphore

dispatch_semaphore 是 GCD 使用信號量控制并發(fā),相比較OSSpinLock等待狀態(tài)消耗 CPU 資源仍秤。?相關(guān)的三個函數(shù):

1.創(chuàng)建信號量熄诡,

2.等待信號

3.發(fā)送信號

dispatch_semaphore_create(long value); dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);

dispatch_semaphore_signal(dispatch_semaphore_t dsema);

?

當設(shè)置信號量為 1 時,一個 dispatch_semaphore_wait(signal, overTime); 方法對應一個 dispatch_semaphore_signal(signal); 類似NSLock 的 lock 和 unlock诗力,區(qū)別在于有信號量這個參數(shù)凰浮,lock unlock 只能同一時間,一個線程訪問被保護的臨界區(qū)苇本,而如果 dispatch_semaphore 的信號量初始值為 x 袜茧,則可以有 x 個線程同時訪問被保護的臨界區(qū),即可以控制多個線程并發(fā)瓣窄。

?

2.5?NSCondition?

NSCondition?的底層是通過條件變量(condition variable)?pthread_cond_t?來實現(xiàn)的笛厦。條件變量有點像信號量,提供了線程阻塞與信號機制俺夕,因此可以用來阻塞某個線程裳凸,并等待某個數(shù)據(jù)就緒,隨后喚醒線程啥么,比如常見的生產(chǎn)者-消費者模式登舞。

示例:

??? ????NSCondition *lock = [[NSCondition alloc] init];

??? //線程1

??????? [lock lock];

??????? [lock wait]; // 線程被掛起

??????? [lock unlock];

??? //線程2

??????? sleep(1);//以保證讓線程2的代碼后執(zhí)行

??????? [lock lock];

??????? [lock signal]; // 喚醒線程1

??????? [lock unlock];


2.6?NSRecursiveLock

遞歸鎖也是通過?pthread_mutex_lock?函數(shù)來實現(xiàn),在函數(shù)內(nèi)部會判斷鎖的類型悬荣,如果顯示是遞歸鎖菠秒,就允許遞歸調(diào)用,僅僅將一個計數(shù)器加一氯迂,鎖的釋放過程也是同理沟使。

NSRecursiveLock?與?NSLock?的區(qū)別在于內(nèi)部封裝的?pthread_mutex_t?對象的類型不同,前者的類型為?PTHREAD_MUTEX_RECURSIVE判哥。


2.7?NSConditionLock

NSConditionLock 可以稱為條件鎖忱叭,只有 condition 參數(shù)與初始化時候的 condition 相等,lock 才能正確進行加鎖操作轿曙。而 unlockWithCondition: 并不是當 Condition 符合條件時才解鎖弄捕,而是解鎖之后僻孝,修改 Condition 的值。


NSConditionLock 借助 NSCondition 來實現(xiàn)守谓,它的本質(zhì)就是一個生產(chǎn)者-消費者模型穿铆。“條件被滿足”可以理解為生產(chǎn)者提供了新的內(nèi)容斋荞。NSConditionLock 的內(nèi)部持有一個 NSCondition 對象荞雏,以及 _condition_value 屬性,在初始化時就會對這個屬性進行賦值:

// 簡化版代碼

- (id) initWithCondition: (NSInteger)value {

??? if (nil != (self = [super init])) {

??????? _condition = [NSCondition new]

??????? _condition_value = value;

??? }

??? return self;

}

它的 lockWhenCondition 方法其實就是消費者方法:

- (void) lockWhenCondition: (NSInteger)value {

??? [_condition lock];

??? while (value != _condition_value) {

??????? [_condition wait];

??? }

}

對應的 unlockWhenCondition 方法則是生產(chǎn)者平酿,使用了 broadcast 方法通知了所有的消費者:

- (void) unlockWithCondition: (NSInteger)value {

??? _condition_value = value;

??? [_condition broadcast];

??? [_condition unlock];

}


2.8??@synchronized

這其實是一個 OC 層面的鎖凤优,主要是通過犧牲性能換來語法上的簡潔與可讀。

@synchronized 后面需要緊跟一個 OC 對象蜈彼,它實際上是把這個對象當做鎖的唯一標識筑辨。這是通過一個哈希表來記錄表示,OC 在底層使用了一個互斥鎖的數(shù)組(你可以理解為鎖池)柳刮,通過對對象去哈希值在數(shù)組中得到對應的互斥鎖挖垛。

示例:

@synchronized(self) {

????? //線程安全代碼

}


3?性能對比

下圖通過加鎖耗時簡單的比較了各種鎖的加解鎖性能

?


性能測試源碼:

https://github.com/ibireme/tmp/blob/master/iOSLockBenckmark/iOSLockBenckmark/ViewController.m

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市秉颗,隨后出現(xiàn)的幾起案子痢毒,更是在濱河造成了極大的恐慌,老刑警劉巖蚕甥,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哪替,死亡現(xiàn)場離奇詭異,居然都是意外死亡菇怀,警方通過查閱死者的電腦和手機凭舶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來爱沟,“玉大人帅霜,你說我怎么就攤上這事『羯欤” “怎么了身冀?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長括享。 經(jīng)常有香客問我搂根,道長,這世上最難降的妖魔是什么铃辖? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任剩愧,我火速辦了婚禮,結(jié)果婚禮上娇斩,老公的妹妹穿的比我還像新娘仁卷。我一直安慰自己穴翩,他們只是感情好,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布锦积。 她就那樣靜靜地躺著藏否,像睡著了一般。 火紅的嫁衣襯著肌膚如雪充包。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天遥椿,我揣著相機與錄音基矮,去河邊找鬼。 笑死冠场,一個胖子當著我的面吹牛家浇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播碴裙,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼钢悲,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了舔株?” 一聲冷哼從身側(cè)響起莺琳,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎载慈,沒想到半個月后惭等,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡办铡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年辞做,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寡具。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡秤茅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出童叠,到底是詐尸還是另有隱情框喳,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布拯钻,位于F島的核電站帖努,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏粪般。R本人自食惡果不足惜拼余,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望亩歹。 院中可真熱鬧匙监,春花似錦凡橱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至达罗,卻和暖如春坝撑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背粮揉。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工巡李, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人扶认。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓侨拦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親辐宾。 傳聞我的和親對象是個殘疾皇子狱从,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

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

  • 鎖是一種同步機制,用于多線程環(huán)境中對資源訪問的限制iOS中常見鎖的性能對比圖(摘自:ibireme): iOS鎖的...
    LiLS閱讀 1,524評論 0 6
  • 線程安全是什么叠纹? 當一個線程訪問數(shù)據(jù)的時候季研,其他的線程不能對其進行訪問,直到該線程訪問完畢誉察。簡單來講就是在同一時刻...
    6ffd6634d577閱讀 2,202評論 1 7
  • 轉(zhuǎn)自(https://bestswifter.com/ios-lock/#) 深入理解 iOS 開發(fā)中的鎖 摘要 ...
    犯色戒的和尚閱讀 321評論 0 1
  • 前言 在多線程開發(fā)中训貌,常會遇到多個線程訪問修改數(shù)據(jù)。為了防止數(shù)據(jù)不一致或數(shù)據(jù)污染冒窍,通常采用加鎖機制來保證線程安全递沪。...
    趙夢楠閱讀 954評論 0 5
  • 在平時的開發(fā)中經(jīng)常使用到多線程,在使用多線程的過程中综液,難免會遇到資源競爭的問題款慨,那我們怎么來避免出現(xiàn)這種問題那? ...
    IAMCJ閱讀 3,099評論 2 25