iOS 十種線程鎖

前言

我覺得打游戲屏蔽臟話挺有必要的, 我走中單, 打野一直拿我藍(lán), 我開大打他路過交懲戒搶, 我氣的不行, 就罵他, 結(jié)果打出來的都是"李白你是不是 * * * ?"妓湘、"搶 * * *的藍(lán)", 我覺得沒氣勢(shì), 沒辦法, 我打了個(gè)"李白你個(gè)大壞蛋", 他就再也沒搶過了, 還掩護(hù)我打藍(lán).

iOS 十種線程鎖.jpeg

鎖 是什么意思?

  • 我們?cè)谑褂枚嗑€程的時(shí)候多個(gè)線程可能會(huì)訪問同一塊資源丰介,這樣就很容易引發(fā)數(shù)據(jù)錯(cuò)亂和數(shù)據(jù)安全等問題,這時(shí)候就需要我們保證每次只有一個(gè)線程訪問這一塊資源鉴分,鎖 應(yīng)運(yùn)而生哮幢。
  • 這里順便提一下,上鎖的兩種方式trylock和lock使用場(chǎng)景:
當(dāng)前線程鎖失敗,也可以繼續(xù)其它任務(wù)志珍,用 trylock 合適
當(dāng)前線程只有鎖成功后橙垢,才會(huì)做一些有意義的工作,那就 lock伦糯,沒必要輪詢 trylock
注:以下大部分鎖都會(huì)提供trylock接口,不再作解釋
感謝yy大神.png

<準(zhǔn)備操作>

測(cè)試代碼
#define RHTICK   NSDate *startTime = [NSDate date];
#define RHTOCK   NSLog(@"==========Time: %f", -[startTime timeIntervalSinceNow]);
NSUInteger count = 1000*10000;//執(zhí)行一千萬次
RHTICK
for(int i=0; i<count; i++) {
加鎖
解鎖
}
RHTOCK
注:測(cè)試中執(zhí)行時(shí)間會(huì)波動(dòng),所以我取的平均值.

一柜某、OSSpinLock (自旋鎖)

測(cè)試中效率最高的鎖, 不過經(jīng)YYKit作者確認(rèn), OSSpinLock已經(jīng)不再線程安全,OSSpinLock有潛在的優(yōu)先級(jí)反轉(zhuǎn)問題.不再安全的 OSSpinLock;

  • 0.097348s
需要導(dǎo)入頭文件
#import <libkern/OSAtomic.h>
// 初始化
 OSSpinLock spinLock = OS_SPINLOCK_INIT;
// 加鎖
OSSpinLockLock(&spinLock);
// 解鎖
OSSpinLockUnlock(&spinLock);
// 嘗試加鎖,可以加鎖則立即加鎖并返回 YES,反之返回 NO
OSSpinLockTry(&spinLock)
/*
注:蘋果爸爸已經(jīng)在iOS10.0以后廢棄了這種鎖機(jī)制,使用os_unfair_lock 替換,
顧名思義能夠保證不同優(yōu)先級(jí)的線程申請(qǐng)鎖的時(shí)候不會(huì)發(fā)生優(yōu)先級(jí)反轉(zhuǎn)問題.
*/

二敛纲、os_unfair_lock(互斥鎖)

  • 0.171789s
需要導(dǎo)入頭文件
#import <os/lock.h>
// 初始化
 os_unfair_lock unfair_lock = OS_UNFAIR_LOCK_INIT;
// 加鎖
os_unfair_lock_lock(&unfair_lock);
// 解鎖
os_unfair_lock_unlock(&unfair_lock);
// 嘗試加鎖喂击,可以加鎖則立即加鎖并返回 YES,反之返回 NO
os_unfair_lock_trylock(&unfair_lock);
/*
注:解決不同優(yōu)先級(jí)的線程申請(qǐng)鎖的時(shí)候不會(huì)發(fā)生優(yōu)先級(jí)反轉(zhuǎn)問題.
不過相對(duì)于 OSSpinLock , os_unfair_lock性能方面減弱了許多.
*/

三、dispatch_semaphore (信號(hào)量)

  • 0.155043s
// 初始化
dispatch_semaphore_t semaphore_t = dispatch_semaphore_create(1);
// 加鎖
dispatch_semaphore_wait(semaphore_t,DISPATCH_TIME_FOREVER);
// 解鎖
dispatch_semaphore_signal(semaphore_t);
/*
注: dispatch_semaphore  其他兩個(gè)功能
1.還可以起到阻塞線程的作用.
2.可以實(shí)現(xiàn)定時(shí)器功能,這里不做過多介紹.
*/

四淤翔、pthread_mutex(互斥鎖)

  • 0.262592s
需要導(dǎo)入頭文件
#import <pthread/pthread.h>
// 初始化(兩種)
1.普通初始化
pthread_mutex_t mutex_t;
pthread_mutex_init(&mutex_t, NULL); 
2.宏初始化
pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER;
// 加鎖
pthread_mutex_lock(&mutex_t);
// 解鎖
pthread_mutex_unlock(&mutex_t);
// 嘗試加鎖翰绊,可以加鎖時(shí)返回的是 0,否則返回一個(gè)錯(cuò)誤
pthread_mutex_trylock(& mutex_t)

五旁壮、NSLock(互斥鎖监嗜、對(duì)象鎖)

  • 0.283196s
// 初始化
NSLock *_lock = [[NSLock alloc]init];
// 加鎖
[_lock lock];
// 解鎖
[_lock unlock];
// 嘗試加鎖,可以加鎖則立即加鎖并返回 YES,反之返回 NO
[_lock tryLock];

六抡谐、NSCondition(條件鎖裁奇、對(duì)象鎖)

  • 0.293046s
// 初始化
NSCondition *_condition= [[NSCondition alloc]init];
// 加鎖
[_condition lock];
// 解鎖
[_condition unlock];
/*
其他功能接口
wait 進(jìn)入等待狀態(tài)
waitUntilDate:讓一個(gè)線程等待一定的時(shí)間
signal 喚醒一個(gè)等待的線程
broadcast 喚醒所有等待的線程
注: 所測(cè)時(shí)間波動(dòng)太大, 有時(shí)候會(huì)快于 NSLock, 我取得中間值.
*/

七、NSConditionLock(條件鎖童叠、對(duì)象鎖)

  • 0.950285s
// 初始化
NSConditionLock *_conditionLock = [[NSConditionLock alloc]init];
// 加鎖
[_conditionLock lock];
// 解鎖
[_conditionLock unlock];
// 嘗試加鎖框喳,可以加鎖則立即加鎖并返回 YES,反之返回 NO
[_conditionLock tryLock];
/*
其他功能接口
- (instancetype)initWithCondition:(NSInteger)condition NS_DESIGNATED_INITIALIZER; //初始化傳入條件
- (void)lockWhenCondition:(NSInteger)condition;//條件成立觸發(fā)鎖
- (BOOL)tryLockWhenCondition:(NSInteger)condition;//嘗試條件成立觸發(fā)鎖
- (void)unlockWithCondition:(NSInteger)condition;//條件成立解鎖
- (BOOL)lockBeforeDate:(NSDate *)limit;//觸發(fā)鎖 在等待時(shí)間之內(nèi)
- (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;//觸發(fā)鎖 條件成立 并且在等待時(shí)間之內(nèi)
*/

八课幕、NSRecursiveLock(遞歸鎖、對(duì)象鎖)

  • 0.473536s
// 初始化
NSRecursiveLock *_recursiveLock = [[NSRecursiveLock alloc]init];
// 加鎖
[_recursiveLock lock];
// 解鎖
[_recursiveLock unlock];
// 嘗試加鎖五垮,可以加鎖則立即加鎖并返回 YES,反之返回 NO
[_recursiveLock tryLock];
/*
注: 遞歸鎖可以被同一線程多次請(qǐng)求乍惊,而不會(huì)引起死鎖。
即在同一線程中在未解鎖之前還可以上鎖, 執(zhí)行鎖中的代碼放仗。
這主要是用在循環(huán)或遞歸操作中润绎。
- (BOOL)lockBeforeDate:(NSDate *)limit;//觸發(fā)鎖 在等待時(shí)間之內(nèi)
*/

九、@synchronized()遞歸鎖

  • 1.101924s
// 初始化
@synchronized(鎖對(duì)象){
}
底層封裝的pthread_mutex的PTHREAD_MUTEX_RECURSIVE 模式,
鎖對(duì)象來表示是否為同一把鎖

更多關(guān)于@synchronized;

十诞挨、pthread_mutex(recursive)(遞歸鎖)

  • 0.372398s
// 初始化
pthread_mutex_t mutex_t;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr); //初始化attr并且給它賦予默認(rèn)pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); //設(shè)置鎖類型莉撇,這邊是設(shè)置為遞歸鎖
pthread_mutex_init(&mutex_t, &attr);
pthread_mutexattr_destroy(&attr); //銷毀一個(gè)屬性對(duì)象,在重新進(jìn)行初始化之前該結(jié)構(gòu)不能重新使用
// 加鎖
pthread_mutex_lock(&mutex_t);
// 解鎖
pthread_mutex_unlock(&mutex_t);
/*
注: 遞歸鎖可以被同一線程多次請(qǐng)求惶傻,而不會(huì)引起死鎖棍郎。
即在同一線程中在未解鎖之前還可以上鎖, 執(zhí)行鎖中的代碼。
這主要是用在循環(huán)或遞歸操作中银室。
*/

性能總結(jié)

OSSpinLock                          0.097348s
dispatch_semaphore                  0.155043s
os_unfair_lock                      0.171789s
pthread_mutex                       0.262592s
NSLock                              0.283196s
pthread_mutex(recursive)            0.372398s
NSRecursiveLock                     0.473536s
NSConditionLock                     0.950285s
@synchronized                       1.101924s
注:建議正常鎖功能用 pthread_mutex ,os_unfair_lock (適配低版本)

鎖的注解

1涂佃、自旋鎖

OSSpinLock 就是典型的自旋鎖
自旋鎖的特點(diǎn)是在沒有獲取到鎖時(shí)既鎖已經(jīng)被添加,還沒有被解開時(shí). 
OSSpinLock處于忙等狀態(tài),一直占用CPU資源,類似如下偽代碼:
while(鎖沒解開);

關(guān)于優(yōu)先級(jí)反轉(zhuǎn)問題
由于線程調(diào)度,每條線程的分配時(shí)間權(quán)重不一樣,當(dāng)權(quán)重小的線程先進(jìn)入OSSpinLock優(yōu)先加鎖,
當(dāng)權(quán)重大的線程再來訪問,就阻塞在這,可能權(quán)重大的線程會(huì)一直分配到cpu所以一直會(huì)進(jìn)來,
但是因?yàn)橛墟i,只能等待,權(quán)重小的線程得不到cpu資源分配,所以不會(huì)解鎖,造成一定程度的死鎖.

2、互斥鎖

os_unfair_lock 蜈敢、pthread_mutex是典型的互斥鎖,在沒有獲取到鎖時(shí)既鎖已經(jīng)被添加,還沒有被解開時(shí). 
它們都會(huì)讓當(dāng)前線程進(jìn)入休眠狀態(tài)既不占用CPU資源,但是為什么,互斥鎖比自旋鎖的效率低呢,
是因?yàn)樾菝?以及喚醒休眠,比忙等更加消耗CPU資源.

NSLock 封裝的pthread_mutex的PTHREAD_MUTEX_NORMAL 模式
NSRecursiveLock 封裝的pthread_mutex的PTHREAD_MUTEX_RECURSIVE 模式

3辜荠、條件鎖

在一定條件下,讓其等待休眠,并放開鎖,等接收到信號(hào)或者廣播,會(huì)從新喚起線程,并重新加鎖.
pthread_cond_wait(&_cond, &_mutex);
 // 信號(hào)
    pthread_cond_signal(&_cond);
 // 廣播
    pthread_cond_broadcast(&_cond);

像NSCondition封裝了pthread_mutex的以上幾個(gè)函數(shù)

NSConditionLock封裝了NSCondition

4、遞歸鎖

遞歸鎖的主要意思是,同一條線程可以加多把鎖.什么意思呢,就是相同的線程訪問一段代碼,
如果是加鎖的可以繼續(xù)加鎖,繼續(xù)往下走,不同線程來訪問這段代碼時(shí),發(fā)現(xiàn)有鎖要等待所有鎖解開之后才可以繼續(xù)往下走.

NSRecursiveLock 封裝的pthread_mutex  的PTHREAD_MUTEX_RECURSIVE模式
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末抓狭,一起剝皮案震驚了整個(gè)濱河市伯病,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌否过,老刑警劉巖午笛,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異苗桂,居然都是意外死亡季研,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門誉察,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人惹谐,你說我怎么就攤上這事持偏。” “怎么了氨肌?”我有些...
    開封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵鸿秆,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我怎囚,道長(zhǎng)卿叽,這世上最難降的妖魔是什么桥胞? 我笑而不...
    開封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮考婴,結(jié)果婚禮上贩虾,老公的妹妹穿的比我還像新娘。我一直安慰自己沥阱,他們只是感情好缎罢,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著考杉,像睡著了一般策精。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上崇棠,一...
    開封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天咽袜,我揣著相機(jī)與錄音,去河邊找鬼枕稀。 笑死询刹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的抽莱。 我是一名探鬼主播范抓,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼食铐!你這毒婦竟也來了匕垫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤虐呻,失蹤者是張志新(化名)和其女友劉穎象泵,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體斟叼,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡偶惠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了朗涩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片忽孽。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖谢床,靈堂內(nèi)的尸體忽然破棺而出兄一,到底是詐尸還是另有隱情,我是刑警寧澤识腿,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布出革,位于F島的核電站,受9級(jí)特大地震影響渡讼,放射性物質(zhì)發(fā)生泄漏骂束。R本人自食惡果不足惜耳璧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望展箱。 院中可真熱鬧旨枯,春花似錦、人聲如沸析藕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽账胧。三九已至竞慢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間治泥,已是汗流浹背筹煮。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留居夹,地道東北人败潦。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像准脂,于是被迫代替她去往敵國(guó)和親劫扒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

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

  • iOS線程安全的鎖與性能對(duì)比 一狸膏、鎖的基本使用方法 1.1沟饥、@synchronized 這是我們最熟悉的枷鎖方式,...
    Jacky_Yang閱讀 2,230評(píng)論 0 17
  • 鎖是一種同步機(jī)制湾戳,用于多線程環(huán)境中對(duì)資源訪問的限制iOS中常見鎖的性能對(duì)比圖(摘自:ibireme): iOS鎖的...
    LiLS閱讀 1,524評(píng)論 0 6
  • 前言 iOS開發(fā)中由于各種第三方庫的高度封裝贤旷,對(duì)鎖的使用很少,剛好之前面試中被問到的關(guān)于并發(fā)編程鎖的問題砾脑,都是一知...
    喵渣渣閱讀 3,712評(píng)論 0 33
  • 引用自多線程編程指南應(yīng)用程序里面多個(gè)線程的存在引發(fā)了多個(gè)執(zhí)行線程安全訪問資源的潛在問題幼驶。兩個(gè)線程同時(shí)修改同一資源有...
    Mitchell閱讀 1,998評(píng)論 1 7
  • 今天北京沙塵+霧霾,好久沒有這種天氣韧衣,還以為污染巳遠(yuǎn)離我們盅藻,錯(cuò)覺了。在外游玩的群友多吸兩口新鮮空氣吧畅铭。 天氣不好萧求,...
    王悅yue閱讀 121評(píng)論 0 4