iOS的各種鎖

本文主要是一個(gè)對(duì)各種鎖的簡(jiǎn)單整理彬犯,方便后續(xù)查看回顧,畢竟鎖在實(shí)際項(xiàng)目中用的比較少田炭,再牛逼的知識(shí)點(diǎn)师抄,老不用也記不住。好記性不如爛筆頭教硫。

說(shuō)到鎖肯定是涉及多線程了叨吮,所以先簡(jiǎn)單的介紹一下iOS里的多線程GCD。
先介紹幾個(gè)比較容易混淆的術(shù)語(yǔ):

  • 同步:在當(dāng)前線程中執(zhí)行任務(wù)瞬矩,不具備開(kāi)啟新線程的能力茶鉴;
  • 異步:在新的線程中執(zhí)行任務(wù),具備開(kāi)啟新線程的能力景用;
  • 并發(fā):多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行蛤铜;
  • 串行:一個(gè)任務(wù)執(zhí)行完成之后,再執(zhí)行下一個(gè)任務(wù)丛肢。

各種隊(duì)列的執(zhí)行效果

并發(fā)隊(duì)列 手動(dòng)創(chuàng)建的串行隊(duì)列 主隊(duì)列
同步(sync) 沒(méi)有開(kāi)啟新的線程围肥;串行執(zhí)行任務(wù) 沒(méi)有開(kāi)啟新的線程;串行執(zhí)行任務(wù) 沒(méi)有開(kāi)啟新的線程蜂怎;串行執(zhí)行任務(wù)
異步(async) 有開(kāi)啟新的線程穆刻;并發(fā)執(zhí)行任務(wù) 有開(kāi)啟新的線程;串行執(zhí)行任務(wù) 沒(méi)有開(kāi)啟新的線程杠步;串行執(zhí)行任務(wù)

注意: 使用sync函數(shù)往當(dāng)前串行隊(duì)列中添加任務(wù)氢伟,會(huì)卡在當(dāng)前的串行隊(duì)列(產(chǎn)生死鎖)

隊(duì)列組的使用

使用GCD實(shí)現(xiàn):異步并發(fā)執(zhí)行任務(wù)1、任務(wù)2幽歼。等任務(wù)1和2執(zhí)行完之后朵锣,回到主線程執(zhí)行任務(wù)3

dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_async(group, queue, ^{
        NSLog(@"執(zhí)行任務(wù)一");
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"執(zhí)行任務(wù)二");
    });
    dispatch_group_notify(group, queue, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"回到主線程執(zhí)行任務(wù)三");
        });
    });

多線程的安全隱患:

  • 當(dāng)多個(gè)線程訪問(wèn)同一塊資源時(shí),很容易引發(fā)數(shù)據(jù)錯(cuò)亂和數(shù)據(jù)安全問(wèn)題甸私。

iOS中的線程同步方案

GNUstep

  • 說(shuō)明:GNUstep是GNU計(jì)劃的項(xiàng)目之一诚些,它將Cocoa的OC庫(kù)重新開(kāi)源實(shí)現(xiàn)的一遍
  • 源碼地址:http://www.gnustep.org/resources/downloads.php
  • 雖然GNUstep不是蘋果官方源碼,但還是有一定的參考價(jià)值

1. OSSpinLock

  • 介紹:OSSpinLock叫做“自旋鎖”,等待所得線程會(huì)處于忙等(busy-wait)狀態(tài)诬烹,一直占用著CPU資源砸烦;
  • 目前已不再安全,可能會(huì)出現(xiàn)優(yōu)先級(jí)反轉(zhuǎn)問(wèn)題绞吁;
  • 如果等待鎖的線程優(yōu)先級(jí)較高幢痘,它會(huì)一直占用著CPU資源,優(yōu)先級(jí)低的線程就無(wú)法釋放鎖家破;
  • 需要導(dǎo)入頭文件 #import <libkern/OSAtomic.h>
  • 使用方法:
    // 初始化
    OSSpinLock lock = OS_SPINLOCK_INIT;
    // 嘗試加鎖(如果需要等待就不加鎖颜说,直接返回false;如果不需要等待汰聋,就加鎖门粪,返回true)
    bool result = OSSpinLockTry(&lock);
    // 加鎖
    OSSpinLockLock(&lock);
    // 解鎖
    OSSpinLockUnlock(&lock);

2. os_unfair_lock

  • 介紹:os_unfair_lock用于取代不安全的OSSpinLock,從iOS10才開(kāi)始支持马僻;
  • 從底層調(diào)用看庄拇,等待os_unfair_lock鎖的線程會(huì)處于休眠狀態(tài),并非忙等韭邓;
  • 需要導(dǎo)入頭文件 #import <os/lock.h>
  • 使用方法:
    // 初始化
    os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
    // 嘗試加鎖(如果需要等待就不加鎖措近,直接返回false;如果不需要等待女淑,就加鎖瞭郑,返回true)
    bool result = os_unfair_lock_trylock(&lock);
    // 加鎖
    os_unfair_lock_lock(&lock);
    // 解鎖
    os_unfair_lock_unlock(&lock);

3. pthread_mutex

  • 介紹:mutex叫做“互斥鎖”,等待鎖的線程會(huì)處于休眠狀態(tài)鸭你∏牛跨平臺(tái)
  • 需要導(dǎo)入頭文件 #import <pthread.h>
  • 使用方法:
    // 初始化鎖的屬性
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
    // 初始化鎖
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, &attr);
    
    // 注意 如果屬性值傳NULL,則屬性的默認(rèn)值為上面的代碼
    <!--pthread_mutex_init(&mutex, NULL);-->
    
    // 嘗試加鎖
    pthread_mutex_trylock(&mutex);
    // 加鎖
    pthread_mutex_lock(&mutex);
    // 解鎖
    pthread_mutex_unlock(&mutex);
    // 銷毀屬性
    pthread_mutexattr_destroy(&attr);
    // 銷毀鎖
    pthread_mutex_destroy(&mutex);

pthread_mutex遞歸鎖

  • 創(chuàng)建時(shí)在初始化屬性的時(shí)候袱巨,傳參為:PTHREAD_MUTEX_RECURSIVE
  • 即:
// 初始化鎖的屬性
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    // 初始化鎖
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, &attr);

pthread_mutex條件鎖

  • 用法:
    // 初始化鎖 NULL代表使用默認(rèn)屬性
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, NULL);
    // 初始化條件
    pthread_cond_t condition;
    pthread_cond_init(&condition, NULL);
    // 等待條件(進(jìn)入休眠阁谆,放開(kāi)mutex鎖,被喚醒后愉老,會(huì)再次對(duì)mutex加鎖)
    pthread_cond_wait(&condition, &mutex);
    // 激活一個(gè)等待該條件的線程
    pthread_cond_signal(&condition);
    // 激活所有等待該條件的線程
    pthread_cond_broadcast(&condition);
    // 銷毀資源
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&condition);

4. dispatch_semaphore

  • 介紹:信號(hào)量鎖
  • 信號(hào)量的初始值场绿,可以用來(lái)控制線程并發(fā)訪問(wèn)的最大數(shù)量;
  • 信號(hào)量的初始值為1嫉入,代表同時(shí)只允許1條線程訪問(wèn)資源焰盗,保證線程同步;
  • 簡(jiǎn)單用法:
    // 初始化信號(hào)量
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    // 如果信號(hào)量的值 <= 0咒林,當(dāng)前線程就會(huì)進(jìn)入休眠等待(直到信號(hào)量的值 > 0)
    // 如果信號(hào)量的值 > 0熬拒,就減1,然后往下執(zhí)行后面的代碼
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    // 讓信號(hào)量的值加1
    dispatch_semaphore_signal(semaphore);

5. dispatch_queue(DISPATCH_QUEUE_SERIAL)

  • 使用GCD的串行隊(duì)列垫竞,也是可以實(shí)現(xiàn)線程同步的
dispatch_queue_t queue = dispatch_queue_create("lock_queue", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        // 任務(wù)
    });

6. NSLock

  • 介紹:NSLock是對(duì)mutex普通鎖的封裝澎粟;
  • 方法API:
- (void)lock;
- (void)unlock;
- (BOOL)tryLock;
- (BOOL)lockBeforeDate:(NSDate *)limit;

7. NSRecursiveLock

  • 介紹:NSRecursiveLock是對(duì)mutex遞歸鎖的封裝;
  • 用法和NSLock基本類似;

8. NSCondition

  • 介紹:NSCondition是對(duì)mutex條件鎖的封裝捌议;
  • 方法API:
- (void)wait;
- (BOOL)waitUntilDate:(NSDate *)limit;
- (void)signal;
- (void)broadcast;

9. NSConditionLock

  • 介紹:NSConditionLock是對(duì)NSCondition的進(jìn)一步封裝哼拔,可以設(shè)置具體的條件值引有;
  • 主要API:
- (instancetype)initWithCondition:(NSInteger)condition NS_DESIGNATED_INITIALIZER;

@property (readonly) NSInteger condition;
- (void)lockWhenCondition:(NSInteger)condition;
- (BOOL)tryLock;
- (BOOL)tryLockWhenCondition:(NSInteger)condition;
- (void)unlockWithCondition:(NSInteger)condition;
- (BOOL)lockBeforeDate:(NSDate *)limit;
- (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;

10. @synchronized

  • 介紹:@synchronized是對(duì)mutex的封裝瓣颅;
  • 源碼查看:objc4中的objc-sync.mm文件;
  • @synchronized(obj)內(nèi)部會(huì)生成obj對(duì)應(yīng)的遞歸鎖譬正,然后進(jìn)行加鎖宫补、解鎖操作;
  • 用法事例:
@synchronized(obj) {
    // 任務(wù)
}

iOS線程同步方案性能大比拼 (從高到低)

  • os_unfair_lock
  • OSSpinLock
  • dispatch_semaphore
  • pthread_mutex
  • dispatch_queue(DISPATCH_QUEUE_SERIAL)
  • NSLock
  • NSCondition
  • pthread_mutex(recursive)
  • NSRecursiveLock
  • NSConditionLock
  • @synchronized

自旋鎖與互斥鎖的比較

什么時(shí)候用自旋鎖比較劃算曾我?

  • 預(yù)計(jì)線程等待鎖的時(shí)間很短粉怕;
  • 加鎖的代碼(臨界區(qū))經(jīng)常被調(diào)用,但競(jìng)爭(zhēng)情況很少發(fā)生抒巢;
  • CPU資源不緊張
  • 多核處理器

什么情況用互斥鎖比較劃算贫贝?

  • 預(yù)計(jì)線程等待鎖的時(shí)間較長(zhǎng);
  • 單核處理器蛉谜;
  • 臨界區(qū)有IO操作稚晚;
  • 臨界區(qū)代碼復(fù)雜或者循環(huán)量較大
  • 臨界區(qū)競(jìng)爭(zhēng)非常激烈;

注意:蘋果其實(shí)不推薦使用自旋鎖

atomic

  • 介紹:atomic用戶保證屬性setter型诚、getter的原子性操作客燕,相當(dāng)于在getter和setter內(nèi)部加了線程同步的鎖;
  • 可以參考o(jì)bjc4的objc-accessors.mm文件
  • 它并不能保證使用屬性的過(guò)程是線程安全的狰贯;

iOS中的讀寫安全方案

應(yīng)用場(chǎng)景:

  • 同一時(shí)間也搓,只能有1個(gè)線程進(jìn)行寫的操作;
  • 同一時(shí)間涵紊,允許有多個(gè)線程進(jìn)行讀的操作傍妒;
  • 同一時(shí)間,不允許既有寫的操作摸柄,又有讀的操作颤练;

對(duì)于上面的“多讀單寫”,經(jīng)常用于文件等數(shù)據(jù)的讀寫操作塘幅,iOS中有兩種方案:

  • pthread_rwlock:讀寫鎖昔案;
  • dispatch_barrier_async:異步柵欄調(diào)用;

pthread_rwlock 用法:

    // 初始化鎖
    pthread_rwlock_t lock;
    // 初始化鎖
    pthread_rwlock_init(&lock, NULL);
    // 讀-加鎖
    pthread_rwlock_rdlock(&lock);
    // 讀-嘗試加鎖
    pthread_rwlock_tryrdlock(&lock);
    // 寫-加鎖
    pthread_rwlock_wrlock(&lock);
    // 寫-嘗試加鎖
    pthread_rwlock_trywrlock(&lock);
    // 解鎖
    pthread_rwlock_unlock(&lock);
    // 銷毀
    pthread_rwlock_destroy(&lock);

dispatch_barrier_async

  • 這個(gè)函數(shù)傳入的并發(fā)隊(duì)列必須是自己通過(guò)dispatch_queue_create創(chuàng)建的
  • 如果傳入的是一個(gè)串行或者一個(gè)全局的并發(fā)隊(duì)列电媳,那么這個(gè)函數(shù)便等同于dispatch_async函數(shù)的效果踏揣;
  • 簡(jiǎn)單用法:
     // 初始化隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("rw_queue", DISPATCH_QUEUE_CONCURRENT);
    // 讀
    dispatch_async(queue, ^{
        
    });
    
    // 寫
    dispatch_barrier_async(queue, ^{
        
    });
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市匾乓,隨后出現(xiàn)的幾起案子捞稿,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件娱局,死亡現(xiàn)場(chǎng)離奇詭異彰亥,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)衰齐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門任斋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人耻涛,你說(shuō)我怎么就攤上這事废酷。” “怎么了抹缕?”我有些...
    開(kāi)封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵澈蟆,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我卓研,道長(zhǎng)趴俘,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任奏赘,我火速辦了婚禮寥闪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘志珍。我一直安慰自己橙垢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布伦糯。 她就那樣靜靜地躺著柜某,像睡著了一般。 火紅的嫁衣襯著肌膚如雪敛纲。 梳的紋絲不亂的頭發(fā)上喂击,一...
    開(kāi)封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音淤翔,去河邊找鬼翰绊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛旁壮,可吹牛的內(nèi)容都是我干的监嗜。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼抡谐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼裁奇!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起麦撵,我...
    開(kāi)封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤刽肠,失蹤者是張志新(化名)和其女友劉穎溃肪,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體音五,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡惫撰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了躺涝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片厨钻。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖诞挨,靈堂內(nèi)的尸體忽然破棺而出莉撇,到底是詐尸還是另有隱情呢蛤,我是刑警寧澤惶傻,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站其障,受9級(jí)特大地震影響银室,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜励翼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一蜈敢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧汽抚,春花似錦抓狭、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至惭蟋,卻和暖如春苗桂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背告组。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工煤伟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人木缝。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓便锨,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親我碟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子放案,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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

  • 線程安全是怎么產(chǎn)生的 常見(jiàn)比如線程內(nèi)操作了一個(gè)線程外的非線程安全變量,這個(gè)時(shí)候一定要考慮線程安全和同步怎囚。 - (v...
    幽城88閱讀 647評(píng)論 0 0
  • demo下載 建議一邊看文章卿叽,一邊看代碼桥胞。 聲明:關(guān)于性能的分析是基于我的測(cè)試代碼來(lái)的,我也看到和網(wǎng)上很多測(cè)試結(jié)果...
    炸街程序猿閱讀 784評(píng)論 0 2
  • 前言 iOS開(kāi)發(fā)中由于各種第三方庫(kù)的高度封裝考婴,對(duì)鎖的使用很少贩虾,剛好之前面試中被問(wèn)到的關(guān)于并發(fā)編程鎖的問(wèn)題,都是一知...
    喵渣渣閱讀 3,685評(píng)論 0 33
  • 鎖是一種同步機(jī)制沥阱,用于多線程環(huán)境中對(duì)資源訪問(wèn)的限制iOS中常見(jiàn)鎖的性能對(duì)比圖(摘自:ibireme): iOS鎖的...
    LiLS閱讀 1,507評(píng)論 0 6
  • “媽媽考杉,爸爸怎么還沒(méi)回家安呔?”顧風(fēng)問(wèn)媽媽崇棠。 “他在外面談生意咽袜,咱不等他,先睡吧枕稀⊙玻”媽媽說(shuō)。 “可是爸爸答應(yīng)我今天給...
    卿訫閱讀 1,350評(píng)論 0 0