多線程和Lock

OC源碼:https://opensource.apple.com/tarballs/objc4/
GCD源碼:https://github.com/apple/swift-corelibs-libdispatch

iOS中常見多線程方案

image.png

同步方庭,異步,串行隊列税灌,并發(fā)隊列之間關(guān)系

同步
  • 主隊列 (沒有開辟新線程 串行執(zhí)行任務(wù))吹害,主隊列本來是同步串行執(zhí)行任務(wù)螟凭,如果再在主隊列同步執(zhí)行任務(wù),會發(fā)生死鎖
  • 并發(fā)隊列 (沒有開辟新線程 串行執(zhí)行任務(wù))
  • 手動創(chuàng)建的串行隊列 (沒有開辟新線程 串行執(zhí)行任務(wù))
異步
  • 主隊列 (沒有開辟新線程 串行執(zhí)行任務(wù))
  • 并發(fā)隊列 (開辟了新線程 并行執(zhí)行任務(wù))
  • 手動創(chuàng)建的串行隊列 (開辟了新線程 串行執(zhí)行任務(wù))

隊列組

//任務(wù)1 任務(wù)2 并發(fā)執(zhí)行 都執(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, ^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"任務(wù)1-%d-%@",i,[NSThread  currentThread]);
        }
    });
    
    dispatch_group_async(group, queue, ^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"任務(wù)2-%d-%@",i,[NSThread  currentThread]);
        }
    });
    
    dispatch_group_notify(group, queue, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            for (int i = 0; i < 5; i++) {
                NSLog(@"任務(wù)3-%d-%@",i,[NSThread  currentThread]);
            }
        });
    });

    //1 2任務(wù)完成后并發(fā)執(zhí)行 4 5
    dispatch_group_notify(group, queue, ^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"任務(wù)4-%d-%@",i,[NSThread  currentThread]);
        }
    });
    
    dispatch_group_notify(group, queue, ^{
        for (int i = 0; i < 5; i++) {
            NSLog(@"任務(wù)5-%d-%@",i,[NSThread  currentThread]);
        }
    });

多線程安全隱患

資源共享
  • 同一塊資源被多個線程訪問
解決方案

常見的線程同步技術(shù)


image.png
  • OSSpinLock 自旋鎖
    等待鎖的線程處于忙等狀態(tài)赠制,一直占用CPU資源赂摆,響應(yīng)快,目前不再安全钟些,有優(yōu)先級反轉(zhuǎn)問題烟号,如果等待鎖的線程優(yōu)先級較高,會一直占用CPU資源政恍,優(yōu)先級低的線程就無法釋放鎖
#import <libkern/OSAtomic.h>

OSSpinLock lock = OS_SPINLOCK_INIT;
//加鎖
OSSpinLockLock(&_lock);
//解鎖
OSSpinLockUnlock(&_lock);
  • os_unfair_lock 互斥鎖
    等待鎖的線程處于休眠狀態(tài)
#import <os/lock.h> 
os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
//加鎖
os_unfair_lock_lock(&_lock);
//解鎖
os_unfair_lock_unlock(&_lock);

*遞歸鎖:允許同一線程多次加鎖汪拥,另一線程執(zhí)行到鎖會等待

  • pthread_mutex
    pthread跨平臺,可以修改屬性成為互斥鎖或者遞歸鎖
image.png

pthread_cond 條件用于線程間通訊


image.png
  • NSLock是對pthread_mutex 普通鎖的封裝
//加鎖
- (void)lock;
//解鎖
- (void)unlock;

- (BOOL)tryLock;  //嘗試加鎖篙耗,不阻塞線程
- (BOOL)lockBeforeDate:(NSDate *)limit;   // 是在指定Date之前嘗試加鎖迫筑,如果在指定時間之前都不能加鎖宪赶,則返回NO。會阻塞線程
  • NSRecursiveLock是對pthread_mutex 遞歸鎖的封裝

  • NSCondition是對pthread_mutex和pthread_cond的封裝

@protocol NSLocking

- (void)lock;
- (void)unlock;

@end


NS_CLASS_AVAILABLE(10_5, 2_0)
@interface NSCondition : NSObject <NSLocking> {
@private
    void *_priv;
}

- (void)wait;
- (BOOL)waitUntilDate:(NSDate *)limit;
- (void)signal;
- (void)broadcast;

@property (nullable, copy) NSString *name API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

@end

  • NSConditionLock是對NSCondition的封裝
  • GCD 串行隊列
  • dispatch_semaphore 信號量
//最大并發(fā)數(shù)是2
dispatch_semaphore_t  semaphore = dispatch_semaphore_create(2);
//判斷當(dāng)前信號量的值是否 > 0, 大于0脯燃,將信號量-1搂妻,執(zhí)行下面的。否則一直休眠等待辕棚。 如果是DISPATCH_TIME_NOW欲主,則大于0,將信號量-1逝嚎,往下執(zhí)行扁瓢,或者小于等于0,則不等补君,往下執(zhí)行
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
//給信號量+1
dispatch_semaphore_signal(self.semaphore);
  • @synchronized是對mutex遞歸鎖的封裝
 @synchronized (<#token#>) {
            <#statements#>
        }

1.打斷點得到圖2匯編代碼調(diào)用


image.png

2.紅框類似于加鎖解鎖操作


圖2

3.在objc源碼objc-sync.mm中找到這兩個方法實現(xiàn)


image.png

4.找到結(jié)構(gòu)體SyncData的定義


image.png

5.跟進成員recursive_mutex_t


image.png

6.跟進recursive_mutex_tt引几,找到構(gòu)造函數(shù),PTHREAD_RECURSIVE_MUTEX_INITIALIZER證明該鎖是遞歸鎖


image.png
性能排序
image.png
自旋鎖和互斥鎖比較

自旋鎖OSSpinLock已經(jīng)廢棄
選用自旋鎖
(1).預(yù)計線程等待鎖的時間很短
(2).加鎖的代碼(臨界區(qū))經(jīng)常被調(diào)用挽铁,但競爭情況很少發(fā)生
(3).CPU資源不緊張時伟桅,多核處理器

選用互斥鎖
(1).預(yù)計線程等待鎖的時間較長
(2).單核處理器
(3).臨界區(qū)有IO操作
(4).臨界區(qū)代碼復(fù)雜
(5).臨界區(qū)競爭激烈

atomic和nonatomic

atomic
(1).給屬性加上atomic,可以保證屬性的set和get都是原子性操作屿储,保證線程同步,查看objc4源碼objc-accessors.mm如下


image.png

(2).不能保證使用屬性的過程是線程安全的
(3).太耗性能

讀寫安全方案(多讀單寫)

(1).同一時間贿讹,只能有1個線程進行寫的操作
(2).同一時間,允許有多個線程進行讀的操作
(3).同一時間够掠,不允許既有寫的操作民褂,又有讀的操作

  • pthread_rwlock 讀寫鎖
    等待鎖的線程會進入休眠
    pthread_rwlock_t rwLock ;
    //初始化
    pthread_rwlock_init(&rwLock, NULL);
    //讀加鎖
    pthread_rwlock_rdlock(&rwLock);
    //寫加鎖
    pthread_rwlock_wrlock(&rwLock);
    //讀寫解鎖
    pthread_rwlock_unlock(&rwLock);
    //鎖銷毀
    pthread_rwlock_destroy(&rwLock);
  • dispatch_barrier_async 異步柵欄調(diào)用
    這個函數(shù)傳入的queue必須是自定義的并發(fā)隊列,如果傳入一個串行或者全局并發(fā)隊列疯潭,則等同于dispatch_async的效果
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    //read
    dispatch_async(queue, ^{
        
    });
    //write
    dispatch_barrier_async(queue, ^{
        
    });
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赊堪,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子竖哩,更是在濱河造成了極大的恐慌哭廉,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件相叁,死亡現(xiàn)場離奇詭異遵绰,居然都是意外死亡,警方通過查閱死者的電腦和手機增淹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門椿访,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人虑润,你說我怎么就攤上這事成玫。” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵哭当,是天一觀的道長猪腕。 經(jīng)常有香客問我,道長钦勘,這世上最難降的妖魔是什么陋葡? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮彻采,結(jié)果婚禮上脖岛,老公的妹妹穿的比我還像新娘。我一直安慰自己颊亮,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布陨溅。 她就那樣靜靜地躺著终惑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪门扇。 梳的紋絲不亂的頭發(fā)上雹有,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天,我揣著相機與錄音臼寄,去河邊找鬼霸奕。 笑死,一個胖子當(dāng)著我的面吹牛吉拳,可吹牛的內(nèi)容都是我干的质帅。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼留攒,長吁一口氣:“原來是場噩夢啊……” “哼煤惩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起炼邀,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤魄揉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后拭宁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體洛退,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年杰标,在試婚紗的時候發(fā)現(xiàn)自己被綠了兵怯。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡在旱,死狀恐怖摇零,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤驻仅,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布谅畅,位于F島的核電站,受9級特大地震影響噪服,放射性物質(zhì)發(fā)生泄漏毡泻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一粘优、第九天 我趴在偏房一處隱蔽的房頂上張望仇味。 院中可真熱鬧,春花似錦雹顺、人聲如沸丹墨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贩挣。三九已至,卻和暖如春没酣,著一層夾襖步出監(jiān)牢的瞬間王财,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工裕便, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留绒净,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓偿衰,卻偏偏與公主長得像挂疆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子哎垦,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,828評論 2 345

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

  • 一囱嫩、簡介:多線程在之前進行過一篇詳細的基礎(chǔ)博客 iOS多線程 二、多線程的基礎(chǔ)知識回顧 1.1漏设、iOS中的常見多線...
    IIronMan閱讀 878評論 0 4
  • Q:為什么出現(xiàn)多線程墨闲? A:為了實現(xiàn)同時干多件事的需求(并發(fā)),同時進行著下載和頁面UI刷新郑口。對于處理器鸳碧,為每個線...
    幸福相依閱讀 1,570評論 0 2
  • 一瞻离、基礎(chǔ)概念 有4個術(shù)語比較容易混淆:同步、異步乒裆、并發(fā)套利、串行 1.進程和線程 進程:進程是計算機中已運行程序的實體...
    666真666閱讀 1,280評論 0 7
  • 心之所向 素履以往 本不是善于表達情感的人 不擅長發(fā)節(jié)日祝福 不擅長回復(fù)祝福 所以寫篇文章寄情吧 今天看到 -至道...
    七雉閱讀 448評論 0 0
  • 在孩子面前,我選擇做一個適當(dāng)懶惰的媽媽,因為你想他動手能力強肉迫,就要忍得住心验辞,舍得放手。 偶爾一次機會喊衫,...
    小小女強人閱讀 1,206評論 3 8