五個案例讓你明白GCD死鎖

死鎖一直都是在使用多線程時,需要注意的一個問題庆锦。以前對同步捅位、異步,串行搂抒、并行只有一個模糊的概念绿渣,想想也是時候整理一下了。再看看之前的博客燕耿,已經(jīng)很久沒有干貨了【說得好像之前有干貨一樣】中符,所以,這篇博客誉帅,我盡最大努力淀散,也借鑒了很多其他博客中的例子,來講解GCD死鎖問題蚜锨。

環(huán)境信息:

Mac OS X 10.10.5

Xcode 6.4

iOS? 8.4

正文


串行與并行

在使用GCD的時候档插,我們會把需要處理的任務(wù)放到Block中,然后將任務(wù)追加到相應(yīng)的隊(duì)列里面亚再,這個隊(duì)列郭膛,叫做Dispatch Queue。然而氛悬,存在于兩種Dispatch Queue则剃,一種是要等待上一個執(zhí)行完,再執(zhí)行下一個的Serial Dispatch Queue如捅,這叫做串行隊(duì)列棍现;另一種,則是不需要上一個執(zhí)行完镜遣,就能執(zhí)行下一個的Concurrent Dispatch Queue己肮,叫做并行隊(duì)列。這兩種,均遵循FIFO原則谎僻。

舉一個簡單的例子娄柳,在三個任務(wù)中輸出1、2艘绍、3赤拒,串行隊(duì)列輸出是有序的1、2鞍盗、3需了,但是并行隊(duì)列的先后順序就不一定了跳昼。

那么般甲,并行隊(duì)列又是怎么在執(zhí)行呢?

雖然可以同時多個任務(wù)的處理鹅颊,但是并行隊(duì)列的處理量敷存,還是要根據(jù)當(dāng)前系統(tǒng)狀態(tài)來。如果當(dāng)前系統(tǒng)狀態(tài)最多處理2個任務(wù)堪伍,那么1锚烦、2會排在前面,3什么時候操作帝雇,就看1或者2誰先完成涮俄,然后3接在后面。

串行和并行就簡單說到這里尸闸,關(guān)于它們的技術(shù)點(diǎn)其實(shí)還有很多彻亲,可以自行了解。

同步與異步

串行與并行針對的是隊(duì)列吮廉,而同步與異步苞尝,針對的則是線程。最大的區(qū)別在于宦芦,同步線程要阻塞當(dāng)前線程宙址,必須要等待同步線程中的任務(wù)執(zhí)行完,返回以后调卑,才能繼續(xù)執(zhí)行下一任務(wù)抡砂;而異步線程則是不用等待。

僅憑這幾句話還是很難理解恬涧,所以之后準(zhǔn)備了很多案例舀患,可以邊分析邊理解。

GCD API

GCD API很多聊浅,這里僅介紹本文用到的。

1. 系統(tǒng)標(biāo)準(zhǔn)提供的兩個隊(duì)列

// 全局隊(duì)列,也是一個并行隊(duì)列

dispatch_get_global_queue

// 主隊(duì)列低匙,在主線程中運(yùn)行旷痕,因?yàn)橹骶€程只有一個,所以這是一個串行隊(duì)列

dispatch_get_main_queue

2. 除此之外顽冶,還可以自己生成隊(duì)列

// 從DISPATCH_QUEUE_SERIAL看出欺抗,這是串行隊(duì)列

dispatch_queue_create("com.demo.serialQueue", DISPATCH_QUEUE_SERIAL)

// 同理,這是一個并行隊(duì)列

dispatch_queue_create("com.demo.concurrentQueue", DISPATCH_QUEUE_CONCURRENT)

接下來是同步與異步線程的創(chuàng)建:

dispatch_sync(..., ^(block)) // 同步線程

dispatch_async(..., ^(block)) // 異步線程

案例與分析

假設(shè)你已經(jīng)基本了解了上面提到的知識强重,接下來進(jìn)入案例講解階段绞呈。

案例一:

NSLog(@"1"); // 任務(wù)1

dispatch_sync(dispatch_get_main_queue(), ^{

NSLog(@"2"); // 任務(wù)2

});

NSLog(@"3"); // 任務(wù)3

結(jié)果,控制臺輸出:

1

分析:

dispatch_sync表示是一個同步線程间景;

dispatch_get_main_queue表示運(yùn)行在主線程中的主隊(duì)列佃声;

任務(wù)2是同步線程的任務(wù)。

首先執(zhí)行任務(wù)1倘要,這是肯定沒問題的圾亏,只是接下來,程序遇到了同步線程封拧,那么它會進(jìn)入等待志鹃,等待任務(wù)2執(zhí)行完,然后執(zhí)行任務(wù)3泽西。但這是隊(duì)列曹铃,有任務(wù)來,當(dāng)然會將任務(wù)加到隊(duì)尾捧杉,然后遵循FIFO原則執(zhí)行任務(wù)陕见。那么,現(xiàn)在任務(wù)2就會被加到最后糠溜,任務(wù)3排在了任務(wù)2前面淳玩,問題來了:

任務(wù)3要等任務(wù)2執(zhí)行完才能執(zhí)行,任務(wù)2由排在任務(wù)3后面非竿,意味著任務(wù)2要在任務(wù)3執(zhí)行完才能執(zhí)行蜕着,所以他們進(jìn)入了互相等待的局面『熘【既然這樣承匣,那干脆就卡在這里吧】這就是死鎖。


案例二:

NSLog(@"1"); // 任務(wù)1

dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

NSLog(@"2"); // 任務(wù)2

});

NSLog(@"3"); // 任務(wù)3

結(jié)果锤悄,控制臺輸出:

1

2

3

分析:

首先執(zhí)行任務(wù)1韧骗,接下來會遇到一個同步線程,程序會進(jìn)入等待零聚。等待任務(wù)2執(zhí)行完成以后袍暴,才能繼續(xù)執(zhí)行任務(wù)3些侍。從dispatch_get_global_queue可以看出,任務(wù)2被加入到了全局的并行隊(duì)列中政模,當(dāng)并行隊(duì)列執(zhí)行完任務(wù)2以后岗宣,返回到主隊(duì)列,繼續(xù)執(zhí)行任務(wù)3淋样。


案例三:

dispatch_queue_t queue = dispatch_queue_create("com.demo.serialQueue", DISPATCH_QUEUE_SERIAL);

NSLog(@"1"); // 任務(wù)1

dispatch_async(queue, ^{

NSLog(@"2"); // 任務(wù)2

dispatch_sync(queue, ^{

NSLog(@"3"); // 任務(wù)3

});

NSLog(@"4"); // 任務(wù)4

});

NSLog(@"5"); // 任務(wù)5


結(jié)果耗式,控制臺輸出:

1

5

2

// 5和2的順序不一定

分析:

這個案例沒有使用系統(tǒng)提供的串行或并行隊(duì)列,而是自己通過dispatch_queue_create函數(shù)創(chuàng)建了一個DISPATCH_QUEUE_SERIAL的串行隊(duì)列趁猴。

1.執(zhí)行任務(wù)1刊咳;

2.遇到異步線程,將【任務(wù)2儡司、同步線程娱挨、任務(wù)4】加入串行隊(duì)列中。因?yàn)槭钱惒骄€程枫慷,所以在主線程中的任務(wù)5不必等待異步線程中的所有任務(wù)完成让蕾;

3.因?yàn)槿蝿?wù)5不必等待浪规,所以2和5的輸出順序不能確定或听;

4.任務(wù)2執(zhí)行完以后,遇到同步線程笋婿,這時誉裆,將任務(wù)3加入串行隊(duì)列;

5.又因?yàn)槿蝿?wù)4比任務(wù)3早加入串行隊(duì)列缸濒,所以足丢,任務(wù)3要等待任務(wù)4完成以后,才能執(zhí)行庇配。但是任務(wù)3所在的同步線程會阻塞斩跌,所以任務(wù)4必須等任務(wù)3執(zhí)行完以后再執(zhí)行。這就又陷入了無限的等待中捞慌,造成死鎖耀鸦。


案例四:

NSLog(@"1"); // 任務(wù)1

dispatch_async(dispatch_get_global_queue(0, 0), ^{

NSLog(@"2"); // 任務(wù)2

dispatch_sync(dispatch_get_main_queue(), ^{

NSLog(@"3"); // 任務(wù)3

});

NSLog(@"4"); // 任務(wù)4

});

NSLog(@"5"); // 任務(wù)5

結(jié)果,控制臺輸出:

1

2

5

3

4

// 5和2的順序不一定

分析:

首先啸澡,將【任務(wù)1袖订、異步線程、任務(wù)5】加入Main Queue中嗅虏,異步線程中的任務(wù)是:【任務(wù)2洛姑、同步線程、任務(wù)4】皮服。

所以楞艾,先執(zhí)行任務(wù)1参咙,然后將異步線程中的任務(wù)加入到Global Queue中,因?yàn)楫惒骄€程硫眯,所以任務(wù)5不用等待昂勒,結(jié)果就是2和5的輸出順序不一定。

然后再看異步線程中的任務(wù)執(zhí)行順序舟铜。任務(wù)2執(zhí)行完以后戈盈,遇到同步線程。將同步線程中的任務(wù)加入到Main Queue中谆刨,這時加入的任務(wù)3在任務(wù)5的后面塘娶。

當(dāng)任務(wù)3執(zhí)行完以后,沒有了阻塞痊夭,程序繼續(xù)執(zhí)行任務(wù)4刁岸。

從以上的分析來看,得到的幾個結(jié)果:1最先執(zhí)行她我;2和5順序不一定虹曙;4一定在3后面。


案例五:

dispatch_async(dispatch_get_global_queue(0, 0), ^{

NSLog(@"1"); // 任務(wù)1

dispatch_sync(dispatch_get_main_queue(), ^{

NSLog(@"2"); // 任務(wù)2

});

NSLog(@"3"); // 任務(wù)3

});

NSLog(@"4"); // 任務(wù)4

while (1) {

}

NSLog(@"5"); // 任務(wù)5

結(jié)果番舆,控制臺輸出:

1

4

// 1和4的順序不一定

分析:

和上面幾個案例的分析類似酝碳,先來看看都有哪些任務(wù)加入了Main Queue:【異步線程、任務(wù)4恨狈、死循環(huán)疏哗、任務(wù)5】。

在加入到Global Queue異步線程中的任務(wù)有:【任務(wù)1禾怠、同步線程返奉、任務(wù)3】。

第一個就是異步線程吗氏,任務(wù)4不用等待芽偏,所以結(jié)果任務(wù)1和任務(wù)4順序不一定。

任務(wù)4完成后弦讽,程序進(jìn)入死循環(huán)污尉,Main Queue阻塞。但是加入到Global Queue的異步線程不受影響坦袍,繼續(xù)執(zhí)行任務(wù)1后面的同步線程十厢。

同步線程中,將任務(wù)2加入到了主線程捂齐,并且蛮放,任務(wù)3等待任務(wù)2完成以后才能執(zhí)行。這時的主線程奠宜,已經(jīng)被死循環(huán)阻塞了包颁。所以任務(wù)2無法執(zhí)行瞻想,當(dāng)然任務(wù)3也無法執(zhí)行,在死循環(huán)后的任務(wù)5也不會執(zhí)行娩嚼。

最終蘑险,只能得到1和4順序不定的結(jié)果。


參考

http://www.reibang.com/p/0b0d9b1f1f19

http://www.cnblogs.com/tangbinblog/p/4133481.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末岳悟,一起剝皮案震驚了整個濱河市佃迄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌贵少,老刑警劉巖呵俏,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異滔灶,居然都是意外死亡普碎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門录平,熙熙樓的掌柜王于貴愁眉苦臉地迎上來麻车,“玉大人,你說我怎么就攤上這事斗这《” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵涝影,是天一觀的道長枣察。 經(jīng)常有香客問我争占,道長燃逻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任臂痕,我火速辦了婚禮伯襟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘握童。我一直安慰自己姆怪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布澡绩。 她就那樣靜靜地躺著稽揭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪肥卡。 梳的紋絲不亂的頭發(fā)上溪掀,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天,我揣著相機(jī)與錄音步鉴,去河邊找鬼揪胃。 笑死璃哟,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的喊递。 我是一名探鬼主播随闪,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼骚勘!你這毒婦竟也來了铐伴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤俏讹,失蹤者是張志新(化名)和其女友劉穎盛杰,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體藐石,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡即供,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了于微。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逗嫡。...
    茶點(diǎn)故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖株依,靈堂內(nèi)的尸體忽然破棺而出驱证,到底是詐尸還是另有隱情,我是刑警寧澤恋腕,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布抹锄,位于F島的核電站,受9級特大地震影響荠藤,放射性物質(zhì)發(fā)生泄漏伙单。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一哈肖、第九天 我趴在偏房一處隱蔽的房頂上張望吻育。 院中可真熱鬧,春花似錦淤井、人聲如沸布疼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽游两。三九已至,卻和暖如春漩绵,著一層夾襖步出監(jiān)牢的瞬間贱案,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工渐行, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留轰坊,地道東北人铸董。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像肴沫,于是被迫代替她去往敵國和親粟害。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評論 2 354

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