ios GCD死鎖

死鎖

1.定義

所謂死鎖,通常指的是兩個線程T1和T2都被卡住沃疮,并等待對方完成某些操作,T1等待T2完成梅肤,T2等待T1完成司蔬,于是大家都完成不了,就造成了死鎖(deadLock)

2.產(chǎn)生死鎖的條件

產(chǎn)生死鎖對的四個必要條件:
(1)互斥條件:一個資源每次只能被一個進程使用
(2)請求與保持條件:一個進程因請求資源而阻塞時姨蝴,對已獲得資源保持不放
(3)不剝奪條件:進程已得到的資源俊啼,在未使用完成之前,不能強行剝奪
(4)循環(huán)等待條件:若干進程之間形成一種頭尾相連的循環(huán)等待資源關(guān)系

這四個條件是死鎖的必要條件左医,只要系統(tǒng)發(fā)生死鎖授帕,這些條件必然成立,只要有一個不滿足浮梢,就不會死鎖

3.圖示

image.png

死鎖代碼:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        dispatch_sync(dispatch_get_main_queue(), ^(void){
            NSLog(@"這里死鎖了");
        });
    }
    return 0;
}
//執(zhí)行這個dispatch_get_main_queue隊列的是主線程跛十,執(zhí)行了dispatch_sync函數(shù)后,將block添加到了main_queue中黔寇,同時調(diào)用這個dispatch_sync函數(shù)的線程被阻塞偶器,等待block完成,而執(zhí)行主線程隊列任務的線程正是主線程缝裤,此時他處于阻塞狀態(tài)屏轰,所以block永遠不會被執(zhí)行,因為主線程一直處于阻塞狀態(tài)憋飞,因此代碼運行之后霎苗,并非卡在了block無法返回,而是根本無法執(zhí)行到這個block

基本概念

1.同步&異步

1.1榛做、同步

同步執(zhí)行:比如這里的dispatch_sync,這個函數(shù)會把一block加入到指定的隊列唁盏,而且會一直等到執(zhí)行完block内狸,這個函數(shù)才會返回,因此在執(zhí)行完blcok之前厘擂,調(diào)用dispatch_sync的線程一直處于阻塞狀態(tài)

1.2昆淡、異步

異步執(zhí)行:dispatch_async,這個函數(shù)會把一個block添加到指定的隊列中刽严,但是和同步執(zhí)行不一樣的是昂灵,這個函數(shù)把block加入隊列后不等block的執(zhí)行就立刻返回。

1.3舞萄、關(guān)于GCD函數(shù)的強調(diào)

dispatch_async 和dispatch_sync 他們的作用是將任務 (block) 添加進指定的隊列中眨补。并根據(jù)是否為sync決定調(diào)用該函數(shù)的線程是否需要阻塞

注意:這里調(diào)用該線程的函數(shù)并不執(zhí)行 參數(shù)中指定的任務(block塊),任務的執(zhí)行者是GCD分配給任務所在隊列的線程倒脓。

結(jié)論:調(diào)用dispatch_async和dispatch_sync線程撑螺,并不一定是任務(block塊)的執(zhí)行者。

2崎弃、串行&并發(fā)

2.1甘晤、串行隊列

串行隊列:比如dispatch_get_main_queue。隊列中所有任務饲做,一定按照FiFo(先進先出)執(zhí)行安皱。不僅如此,還可以保證在執(zhí)行某個任務時艇炎,在他前面進入隊列的所有任務肯定執(zhí)行完了對于每一個不同的串行隊列,系統(tǒng)都會為這個隊列建立唯一的線程來執(zhí)行代碼

2.2腾窝、并發(fā)隊列

比如dispatch_get_global_queue缀踪。這個隊列中的任務也是按照先進先出的順序執(zhí)行,但是他們執(zhí)行結(jié)束的時間是不確定的虹脯,取決于每個任務的耗時驴娃,并發(fā)隊列中的任務:GCD會動態(tài)分配多條線程來執(zhí)行,具體幾條線程取決于當前內(nèi)存使用狀況循集,線程池中線程數(shù)等因素唇敞。

3、總結(jié)

3.1咒彤、異步執(zhí)行block肯定不會發(fā)生死鎖疆柔,回顧一下導致死鎖的原因,是因為主線程在執(zhí)行dispatch_sync镶柱,這是一個同步方法旷档,block執(zhí)行完成之前都不會返回。而async是異步的執(zhí)行歇拆,是立刻返回的鞋屈,因此不會阻塞主線程范咨,雙向的阻塞不成立,只是主線程處理block時候阻塞厂庇,這不會引起死鎖

3.2渠啊、同步的向并發(fā)隊列添加block不會導致死鎖

原因:由于之前在串行隊列中添加了block,block一直要等待前面的任務處理完成才會執(zhí)行权旷,從而造成了死鎖替蛉。如果采用同步的向并發(fā)隊列中添加block,首先需要明確一點炼杖,就是同步方法是不會再開線程的灭返,也就是說當前的調(diào)用線程會立即去執(zhí)行block,直到block執(zhí)行完成后才會繼續(xù)向下執(zhí)行坤邪。因為是并發(fā)隊列熙含,隊列中的下一個任務執(zhí)行不需要等待上一個任務的完成,所以艇纺,即使添加到當前調(diào)用任務的隊列也不會造成死鎖怎静,當前線程會立即執(zhí)行新添加的任務,然后返回黔衡,并繼續(xù)向下執(zhí)行

dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"11111====current thread :%@",[NSThread currentThread]);
        dispatch_sync(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"222====current thread :%@",[NSThread currentThread]);
        });
        NSLog(@"333333333");
    });

結(jié)果:
[10324:5277752] 11111====current thread :<NSThread: 0x60400027f3c0>{number = 3, name = (null)}
[10324:5277752] 222====current thread :<NSThread: 0x60400027f3c0>{number = 3, name = (null)}
[10324:5277752] 333333333
我們可以看到蚓聘,并發(fā)隊列中:同一條線程在上一個任務沒有完成的情況下,可以去執(zhí)行下一個任務盟劫。因為并發(fā)隊列中下一個任務的執(zhí)行不需要上一個任務執(zhí)行完成夜牡。

3.2、如果同步向另一個串行隊列添加方法侣签,并不一定會造成死鎖塘装。

dispatch_queue_t queue = dispatch_queue_create("simple",nil);
dispatch_sync(queue,^(void){
nslog(@"哈哈哈哈")
});
因為:simple這個隊列的執(zhí)行線程是主線程,同步方法不會開辟新線程影所,但這個是將任務添加到了simple這個隊列中蹦肴,所以主線程會立即來執(zhí)行這個隊列中的任務,執(zhí)行完后就會返回猴娩,因此主線程不會繼續(xù)被阻塞阴幌,所以不會死鎖

造成死鎖的唯一原因:

在某一串行隊列中,同步的向這個串行隊列添加block

因為隊列是可以嵌套的卷中,比如在A隊列(串行)添加一個任務a矛双,在a這個任務中像B隊列(串行)添加任務b,在b這個任務中又向A隊列添加任務蟆豫,這間接滿足了“在某一個串行隊列中背零,同步的向這個隊列添加block”。但是我們好像每一次都沒有直接向相同的隊列添加block

所以:判斷是否發(fā)生死鎖的最好方法就是看有沒有在串行隊列(包括主隊列)中向這個隊列添加任務

我們使用同步的方法編程无埃,往往是要求保證人物之間的執(zhí)行順序是完全正確的徙瓶。且不說GCD提供了很多強大的功能來滿足這個需求毛雇,向串行隊列在同步的添加任務本身就是不合理的,畢竟隊列已經(jīng)是串行了侦镇,直接異步添加就可以了

dispatch_queue_t queue = dispatch_queue_create("test.gcd", DISPATCH_QUEUE_SERIAL);
        
dispatch_apply(3, queue, ^(size_t i) {
NSLog(@"apply loop: %zu", i);
    
    //再來一個dispatch_apply灵疮!死鎖!      
dispatch_apply(3, queue, ^(size_t j) {
NSLog(@"apply loop inside %zu", j);
});
});
dsipatch_apply嵌套使用也會死鎖
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末壳繁,一起剝皮案震驚了整個濱河市震捣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌闹炉,老刑警劉巖蒿赢,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異渣触,居然都是意外死亡羡棵,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門嗅钻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來皂冰,“玉大人,你說我怎么就攤上這事养篓⊥毫鳎” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵柳弄,是天一觀的道長舶胀。 經(jīng)常有香客問我,道長碧注,這世上最難降的妖魔是什么峻贮? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮应闯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘挂捻。我一直安慰自己碉纺,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布刻撒。 她就那樣靜靜地躺著骨田,像睡著了一般。 火紅的嫁衣襯著肌膚如雪声怔。 梳的紋絲不亂的頭發(fā)上态贤,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音醋火,去河邊找鬼悠汽。 笑死箱吕,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的柿冲。 我是一名探鬼主播茬高,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼假抄!你這毒婦竟也來了怎栽?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤宿饱,失蹤者是張志新(化名)和其女友劉穎熏瞄,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谬以,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡强饮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蛉签。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胡陪。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖碍舍,靈堂內(nèi)的尸體忽然破棺而出柠座,到底是詐尸還是另有隱情,我是刑警寧澤片橡,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布妈经,位于F島的核電站,受9級特大地震影響捧书,放射性物質(zhì)發(fā)生泄漏吹泡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一经瓷、第九天 我趴在偏房一處隱蔽的房頂上張望爆哑。 院中可真熱鬧,春花似錦舆吮、人聲如沸揭朝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽潭袱。三九已至,卻和暖如春锋恬,著一層夾襖步出監(jiān)牢的瞬間屯换,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工与学, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留彤悔,地道東北人嘉抓。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像蜗巧,于是被迫代替她去往敵國和親掌眠。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

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