iOS 筆記 - 鎖

今天簡單寫一下iOS中相關鎖的內容作瞄,下圖來自不再安全的 OSSpinLock中幾種常見的鎖加解鎖的時間茶宵。

image

以下為我自己測試的結果,加上了iOS10以后的 os_unfair_lock_lock

OSSpinLock:                 333.91 ms
os_unfair_lock_lock:        420.40 ms
dispatch_semaphore:         374.38 ms
pthread_mutex:              459.84 ms
NSCondition:                465.79 ms
NSLock:                     470.10 ms
pthread_mutex(recursive):   800.02 ms
NSRecursiveLock:            712.30 ms
//多次測試NSRecursiveLock與pthread_mutex的遞歸鎖各有先后宗挥,水平有限不知道為啥
//還請有知道的大神不吝賜教乌庶。
NSConditionLock:           1581.54 ms
@synchronized:             1980.12 ms
---- 加解鎖 (10000000)次  測試設備 6s-iOS11.4 ----

廢棄的OSSpinLock

OSSpinLock(自旋鎖)是屬于busy-waiting類型的鎖种蝶,與互斥鎖不同,當SpinLock被其它線程持有瞒大,spinLock不會被阻塞螃征,而會一直的請求獲取lock,從而消耗大量cpu資源透敌。所以當臨界區(qū)任務時間較長時盯滚,并不適合用SpinLock。但當任務時間較短酗电,其效率賊高魄藕。

另外開頭已經提到 OSSpinLock之所以不再使用,是因為當?shù)蛢?yōu)先級的線程獲得了鎖顾瞻,這時一個高優(yōu)先級的線程也嘗試獲得這個鎖泼疑,它會處于 spin lock 的忙等狀態(tài)從而占用大量 CPU,此時低優(yōu)先級線程無法與高優(yōu)先級線程爭奪 CPU 時間荷荤,導致任務無法完成退渗。這就是優(yōu)先級反轉。

時間片輪轉算法蕴纳,每個線程會被分配一段時間片(quantum)会油,通常在 10-100 毫秒左右。當線程用完屬于自己的時間片以后,就會被操作系統(tǒng)掛起,放入等待隊列中梯投,直到下一次被分配時間片。

os_unfair_lock_t

os_unfair_lock_t是官方推薦的替代OSSpinLock的方案嫂冻,優(yōu)化了優(yōu)先級反轉問題。

 os_unfair_lock_t lock = &(OS_UNFAIR_LOCK_INIT);;
 os_unfair_lock_lock(lock);
 os_unfair_lock_unlock(lock);
dispatch_semaphore

dispatch_semaphore 是信號量塞椎,但當信號總量設為 1 時也可以當作鎖來使用桨仿。在沒有等待情況出現(xiàn)時,它的性能比 pthread_mutex 還要高案狠。但一旦有等待情況出現(xiàn)時服傍,會線程進入睡眠狀態(tài),主動讓出時間片骂铁,讓出時間片會導致操作系統(tǒng)切換到另一個線程吹零,這就是所謂的上下文切換,通常需要 10 微秒左右拉庵,而且至少需要兩次切換灿椅。如果等待時間很短,比如只有幾個微秒,忙等就比線程睡眠更高效阱扬。
關于dispatch_semaphore在深入理解GCD中寫的也很詳細泣懊。

dispatch_semaphore_t lock =  dispatch_semaphore_create(1);
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
dispatch_semaphore_signal(lock);
NSLock & pthread_mutex

POSIX線程(POSIX threads),簡稱Pthreads麻惶,是線程的POSIX標準。該標準定義了創(chuàng)建和操縱線程的一整套API信夫。
pthread_mutex 表示互斥鎖窃蹋。互斥鎖的實現(xiàn)原理與信號量非常相似静稻,不是使用忙等警没,而是阻塞線程并睡眠,需要進行上下文切換振湾。
NSLock底層也是使用pthread_mutex實現(xiàn)杀迹,屬性為PTHREAD_MUTEX_ERRORCHECK,因為多了方法發(fā)送等流程押搪,多次調用后因為方法緩存兩者的差距很小树酪。

pthread_mutex_t lock;
pthread_mutex_init(&lock, NULL);
pthread_mutex_lock(&lock);
pthread_mutex_unlock(&lock);

NSLock *lock = [NSLock new];
[lock lock];
[lock unlock];
pthread_mutex(recursive)& NSRecursiveLock

NSRecursiveLock與NSLock類似,也是使用pthread_mutex實現(xiàn)大州,只是類型為 PTHREAD_MUTEX_RECURSIVE续语。
一般情況下,一個線程只能申請一次鎖厦画,也只能在獲得鎖的情況下才能釋放鎖疮茄,多次申請鎖或釋放未獲得的鎖都會導致崩潰。假設在已經獲得鎖的情況下再次申請鎖根暑,線程會因為等待鎖的釋放而進入睡眠狀態(tài)力试,因此就不可能再釋放鎖,從而導致死鎖排嫌。
然而這種情況經常會發(fā)生畸裳,比如某個函數(shù)申請了鎖,在臨界區(qū)內又遞歸調用了自己躏率,由此也就引出了遞歸鎖:允許同一個線程在未釋放其擁有的鎖時反復對該鎖進行加鎖操作躯畴。

pthread_mutex_t lock;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&lock, &attr);
pthread_mutexattr_destroy(&attr);
pthread_mutex_lock(&lock);
//do work
pthread_mutex_unlock(&lock);
NSCondition

NSCondition 其實是封裝了一個互斥鎖和條件變量, 它把前者的 lock 方法和后者的 wait/signal 統(tǒng)一在 NSCondition 對象中薇芝,暴露給使用者蓬抄。所以與NSLock基本類似,性能也很接近夯到。

NSCondition *lock = [NSCondition new];
[lock lock];
//do work
[lock unlock];

NSConditionLock 借助 NSCondition 來實現(xiàn)嚷缭,它的本質就是一個生產者-消費者模型。“條件被滿足”可以理解為生產者提供了新的內容阅爽。NSConditionLock 的內部持有一個 NSCondition 對象路幸,以及 _condition_value 屬性,在初始化時就會對這個屬性進行賦值付翁。
它的 lockWhenCondition 方法其實就是消費者方法:

- (void) lockWhenCondition: (NSInteger)value {
    [_condition lock];
    while (value != _condition_value) {
        [_condition wait];
    }
}

對應的 unlockWhenCondition 方法則是生產者简肴,使用了 broadcast 方法通知了所有的消費者:

- (void) unlockWithCondition: (NSInteger)value {
    _condition_value = value;
    [_condition broadcast];
    [_condition unlock];
}
@synchronized

從上圖可以看出@synchronized 性能是最差,語法最為簡單
每個調用 sychronized 的對象百侧,Objective-C runtime 都會為其分配一個遞歸鎖并存儲在哈希表中砰识。
具體實現(xiàn)可以看這關于 @synchronized,這兒比你想知道的還要多

@synchronized(object) {
        //do work
    }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末佣渴,一起剝皮案震驚了整個濱河市辫狼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌辛润,老刑警劉巖膨处,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異砂竖,居然都是意外死亡真椿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門晦溪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瀑粥,“玉大人,你說我怎么就攤上這事三圆∧唬” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵舟肉,是天一觀的道長修噪。 經常有香客問我,道長路媚,這世上最難降的妖魔是什么黄琼? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮整慎,結果婚禮上脏款,老公的妹妹穿的比我還像新娘。我一直安慰自己裤园,他們只是感情好撤师,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拧揽,像睡著了一般剃盾。 火紅的嫁衣襯著肌膚如雪腺占。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天痒谴,我揣著相機與錄音衰伯,去河邊找鬼。 笑死积蔚,一個胖子當著我的面吹牛意鲸,可吹牛的內容都是我干的。 我是一名探鬼主播尽爆,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼临扮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了教翩?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤贪壳,失蹤者是張志新(化名)和其女友劉穎饱亿,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體闰靴,經...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡彪笼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蚂且。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片配猫。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖杏死,靈堂內的尸體忽然破棺而出泵肄,到底是詐尸還是另有隱情,我是刑警寧澤淑翼,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布腐巢,位于F島的核電站,受9級特大地震影響玄括,放射性物質發(fā)生泄漏冯丙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一遭京、第九天 我趴在偏房一處隱蔽的房頂上張望胃惜。 院中可真熱鬧,春花似錦哪雕、人聲如沸船殉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捺弦。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間列吼,已是汗流浹背幽崩。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留寞钥,地道東北人慌申。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像理郑,于是被迫代替她去往敵國和親蹄溉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內容