GCD - 死鎖 [ 轉(zhuǎn)載 ]

轉(zhuǎn)載的一位大牛的GCD死鎖分析感覺很不錯(cuò),在此分享(http://www.cnblogs.com/LDSmallCat/p/4910080.html)

一.首先來看這段 正確的 代碼:
在touchesbegan中調(diào)用test方法,可以看到如下打印

827473-20151026001309333-1906771235.png

分析一下原理:
1>調(diào)用test方法執(zhí),行到25行時(shí)沒有開啟線程,在主線程中打印
2> 執(zhí)行到31行時(shí)檢測(cè)到異步函數(shù)async,此時(shí)async函數(shù)直接返回,不會(huì)等函數(shù)中的block1執(zhí)行完畢就返回,執(zhí)行到31行系統(tǒng)有兩件事要做,第一跳至42行打印,第二開啟一個(gè)新的線程1(是子線程而非主線程)執(zhí)行block1當(dāng)中的內(nèi)容.所以看到主線程0,4先打印,打印結(jié)束就沒有主線程的事情了,接下來子線程登場(chǎng).()
3> 子線程1執(zhí)行block1的內(nèi)容:
3.1執(zhí)行33行打印 在(子線程1) 打印
3.2執(zhí)行到35行檢測(cè)到async異步函數(shù),直接返回,不等待block2執(zhí)行完畢,程序繼續(xù)向下執(zhí)行,即打印39行 3 子線程打印,同時(shí)又創(chuàng)建一個(gè) (子線程2)
4> ok 到這里我們還需要分析一下,程序運(yùn)行到這里我們一共經(jīng)歷了幾個(gè)線程?三個(gè)!主線程一個(gè),31行 35行分別創(chuàng)建了兩個(gè)子線程1和2
(怎么看是否創(chuàng)建了新的線程?"一般"來說看函數(shù),是async異步執(zhí)行還是sync同步執(zhí)行,為什么要用"一般"?往下看)
那么問題來了1> 33行和 39行的打印(即1,3打印)都在一個(gè)線程上我們可以理解(看線程地址),但是為什么36行的打印 也和這兩個(gè) 在 同一個(gè)線程呢? 因?yàn)?1行創(chuàng)建了一個(gè)子線程 打印了33行和39行之后,這個(gè)線程的任務(wù)結(jié)束了,正常來說就要銷毀了,沒他什么事了.但是我們?cè)?5行又需要?jiǎng)?chuàng)建一個(gè)線程,創(chuàng)建線程需要時(shí)間和空間成本(占用內(nèi)存)所以在子線程1執(zhí)行完任務(wù)進(jìn)入線程池要銷毀的時(shí)候,發(fā)現(xiàn)系統(tǒng)還要再創(chuàng)建一個(gè)線程,ok那我就不銷毀了,你也不用再創(chuàng)建了,所以線程1就被重復(fù)利用了,所以他們?cè)谝粋€(gè)線程上打印.關(guān)于為什么在同一個(gè)子線程上打印,我給出的只是一個(gè)理解的方式,是不是準(zhǔn)確的?我不確定.因?yàn)榫€程很多的情況十分復(fù)雜,我們這個(gè)事例程序很簡(jiǎn)單,可以這樣理解.所以我前面說的是有問題的,這個(gè)程序只經(jīng)歷了兩個(gè)線程,主線程和同一個(gè)子線程
5>ok我們回來 在子線程1執(zhí)行33 39行的打印之后,被系統(tǒng)重復(fù)利用,來執(zhí)行35行block的內(nèi)容,36行打印結(jié)束一個(gè)消息循環(huán)結(jié)束,進(jìn)入休眠等待下次觸摸屏幕.
6>總結(jié):為什么程序的打印結(jié)果會(huì)是這樣的?與兩個(gè)因素有關(guān)1>函數(shù) 是async異步執(zhí)行還是sync同步執(zhí)行2>隊(duì)列我們創(chuàng)建的是串行隊(duì)列這個(gè)串行隊(duì)列里面有兩個(gè)任務(wù) block1 和block2,串行隊(duì)列遵循fifo原則:first in first out,就先進(jìn)先出原則,blokc1在31行加入,先執(zhí)行,block2在35行加入后執(zhí)行.block1中有三個(gè)任務(wù)33行39行打印和block2,且block2在兩個(gè)打印中間,按照程序自上到下執(zhí)行…尼瑪問題又來了,為什么block2不是在兩個(gè)打印任務(wù)之間執(zhí)行?而是在打印結(jié)束后執(zhí)行?ok 這時(shí)就要看函數(shù)啦~async 這是什么?異步執(zhí)行!!要開啟新的線程(或是重復(fù)利用線程池中已經(jīng)創(chuàng)建的線程,什么樣的線程可以重復(fù)利用?這個(gè)線程已經(jīng)執(zhí)行完它的任務(wù),進(jìn)入線程池馬上銷毀的線程才可以重復(fù)利用)(開啟線程或是獲取線程池中重復(fù)利用的線程是需要時(shí)間成本的)檢測(cè)到這個(gè)函數(shù)怎么辦?直接返回,不用等這個(gè)函數(shù)的block執(zhí)行完就返回.什么意思?執(zhí)行到35行的時(shí)候兵分兩路,一路向下執(zhí)行39行打印,一路從線程池中獲取重復(fù)利用的線程處理block2的任務(wù).在兵分兩路的時(shí)候子線程以還沒有處理完39行的打印,它的任務(wù)沒有結(jié)束啊!為什么處理block2沒有創(chuàng)建新的線程?因?yàn)樾枰獣r(shí)間和控件成本.GCD為我們做了優(yōu)化,(怎么優(yōu)化的我們不用操心~看不到源碼這是個(gè)迷,不過看到了也不一定看得懂!哈哈所以不創(chuàng)建新的線程,等子線程1執(zhí)行完他的任務(wù),我們重復(fù)利用它!ok說完了,

二.了解了上圖,我們?cè)賮砜聪旅娴拇a


827473-20151026001405974-1989316509.png

我把35行的函數(shù)換成了sync同步執(zhí)行函數(shù),看打印結(jié)果,2.3沒有打印!這就是傳說中的死鎖.什么意思?36 ,39行沒有打印,程序在等待,卡住了.不能正常向下執(zhí)行了!

分析一下原因:

1>點(diǎn)擊屏幕調(diào)用test方法,主線程打印25行42行,主線程不用我們創(chuàng)建.系統(tǒng)自動(dòng)創(chuàng)建.上面已經(jīng)提到原理就不再贅述,直接來重點(diǎn)

2>31行代碼做了這幾件事:1將block1任務(wù)添加到隊(duì)列串行queue中,2>利用async函數(shù)開啟新的子線程1處理block1任務(wù).

3>當(dāng)執(zhí)行到35行代碼時(shí)做了這幾件事情:1>將block2添加到串行隊(duì)列queue中,2>sync函數(shù)不會(huì)開啟新的線程,只能在當(dāng)前線程執(zhí)行任務(wù)

4>ok現(xiàn)在我們分析一下是什么情況:1>queue當(dāng)中有兩個(gè)任務(wù),block1和block2.2>只有一個(gè)線程:子線程1,在31行創(chuàng)建的.queue串行執(zhí)行任務(wù),要等block1執(zhí)行完才能執(zhí)行block2任務(wù).啥意思?31行創(chuàng)建的子線程1要執(zhí)行完block1才能執(zhí)行block2.執(zhí)行到35行block2任務(wù)的時(shí)候要等待block1執(zhí)行完,可是程序自上而下執(zhí)行,尼瑪block2不執(zhí)行完block1就不會(huì)執(zhí)行完!你懂了么?block2所在的是sync函數(shù)不能開啟新的線程,只能和block1共用一個(gè)線程,這個(gè)線程在處理block1,現(xiàn)在的問題是沒有線程處理block2的任務(wù)~!!!所以就出現(xiàn)了傳說中的死鎖!別尼瑪問我為啥主線程不處理block2的任務(wù)!我會(huì)讓你的老板開除你的!還沒懂?最后說一遍:程序自上而下執(zhí)行知道吧?那么block1執(zhí)行完時(shí)不時(shí)需要block1里面的所有代碼都執(zhí)行完啊?可是到了35行block2沒有開啟新的線程,只能和block1共用一個(gè)線程,現(xiàn)在這個(gè)線程在處理block1的任務(wù),要等block1執(zhí)行完才能執(zhí)行block2的任務(wù).所以程序就卡住了.ok還不懂?看上面正確的代碼第35行我們呢用的是async函數(shù),它能開啟一個(gè)全新的線程來處理block2任務(wù),且不用等到block2執(zhí)行完這個(gè)函數(shù)就返回了!函數(shù)返回啥意思----就是繼續(xù)向下執(zhí)行了.ok說完了.別告訴我你還沒

三:有了上面的分析相信小伙伴們有了一定的了解,再來分析一下下面的代碼是不是死鎖?
所在哪里了?


827473-20151025204741380-1238287898.png

死鎖,鎖在64行的代碼.
分析一下原因:
1>主線程執(zhí)行47, 71行打印之后進(jìn)入 休眠狀態(tài)等待下次點(diǎn)擊屏幕,在兩個(gè)打印之間檢測(cè)到54行async不等block1執(zhí)行完繼續(xù)向下.ok沒問題
2>54行將block1加入到queue隊(duì)列,開async函數(shù)開啟新的線程執(zhí)行block1,block1任務(wù)代碼書訊執(zhí)行 56行打印
3>58行檢測(cè)到async函數(shù)不等block2執(zhí)行完繼續(xù)向下執(zhí)行,62行打印,
4>執(zhí)行到64行 sync函數(shù) 沒有開啟新的線程,要和block1共用一個(gè)線程,造成死鎖
5>分析一下現(xiàn)在什么情況:queue中有3個(gè)任務(wù),block1,block2,block3,順序執(zhí)行,為什么卡在64行?不是58行?58行開啟了一個(gè)新的線程來處理block2,所以不是這里.block3沒有開啟線程要用別人的線程,用誰的呢?你看它在哪個(gè)block里.她在block1里面,block1在54行開啟了線程正在處理block1,所以現(xiàn)在block2沒人處理.就造成死鎖.
6>那么為什么block2沒有打印呢?有線程處理他的任務(wù)啊?這是要看隊(duì)列queue,三個(gè)任務(wù)順序執(zhí)行,block1執(zhí)行完了么?沒有,所以block2不會(huì)打印.ok說完了!有疑問?block2?好吧 來看下面代碼.我把64行的函數(shù)換了.


827473-20151025204817349-1738359650.png

為什么是這個(gè)打印順序呀?
1>主線程優(yōu)先處理,所以 0,6先打印,
2>為什么135這個(gè)順序打印丫?135在同一個(gè)線程中,即block1的線程中,代碼順序執(zhí)行,所以這個(gè)順序
3>為什么2,4打印不是穿插在1,3,5之間呢?1>因?yàn)?打印要開啟新的線程,有時(shí)間成本,啥意思,就是我開啟一個(gè)線程需要時(shí)間.所以他要晚
2>135在主線程,優(yōu)先于子線程處理任務(wù),優(yōu)先級(jí)就比子線程高,所以它晚
3>async函數(shù)不等待后面block執(zhí)行完就向下執(zhí)行,所以它晚,
4>為什么2,4打印沒有開啟兩個(gè)線程而是一個(gè)線程,因?yàn)殚_啟新的線程需要時(shí)間和控件成本GCD為我們自動(dòng)做了優(yōu)化,重復(fù)利用了線程池中執(zhí)行完本職任務(wù)即將銷毀的線程.
5>為什么24的打印順序是這樣:1>因?yàn)?利用了2的線程,(看線程地址)代碼自上而下執(zhí)行,queue中block2排在block3之前,所以要block2打印完才能打印block3.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末慈俯,一起剝皮案震驚了整個(gè)濱河市唯灵,隨后出現(xiàn)的幾起案子摊求,更是在濱河造成了極大的恐慌,老刑警劉巖恨诱,帶你破解...
    沈念sama閱讀 211,376評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異骗炉,居然都是意外死亡照宝,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門句葵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來厕鹃,“玉大人,你說我怎么就攤上這事乍丈〖敛辏” “怎么了?”我有些...
    開封第一講書人閱讀 156,966評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵轻专,是天一觀的道長忆矛。 經(jīng)常有香客問我,道長请垛,這世上最難降的妖魔是什么催训? 我笑而不...
    開封第一講書人閱讀 56,432評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮宗收,結(jié)果婚禮上漫拭,老公的妹妹穿的比我還像新娘。我一直安慰自己镜雨,他們只是感情好嫂侍,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評(píng)論 6 385
  • 文/花漫 我一把揭開白布儿捧。 她就那樣靜靜地躺著荚坞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪菲盾。 梳的紋絲不亂的頭發(fā)上颓影,一...
    開封第一講書人閱讀 49,792評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音懒鉴,去河邊找鬼诡挂。 笑死,一個(gè)胖子當(dāng)著我的面吹牛临谱,可吹牛的內(nèi)容都是我干的璃俗。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼悉默,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼城豁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起抄课,我...
    開封第一講書人閱讀 37,701評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤唱星,失蹤者是張志新(化名)和其女友劉穎雳旅,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體间聊,經(jīng)...
    沈念sama閱讀 44,143評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡攒盈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了哎榴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片型豁。...
    茶點(diǎn)故事閱讀 38,626評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖尚蝌,靈堂內(nèi)的尸體忽然破棺而出偷遗,到底是詐尸還是另有隱情,我是刑警寧澤驼壶,帶...
    沈念sama閱讀 34,292評(píng)論 4 329
  • 正文 年R本政府宣布氏豌,位于F島的核電站,受9級(jí)特大地震影響热凹,放射性物質(zhì)發(fā)生泄漏泵喘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評(píng)論 3 313
  • 文/蒙蒙 一般妙、第九天 我趴在偏房一處隱蔽的房頂上張望纪铺。 院中可真熱鬧,春花似錦碟渺、人聲如沸鲜锚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芜繁。三九已至,卻和暖如春绒极,著一層夾襖步出監(jiān)牢的瞬間骏令,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工垄提, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留榔袋,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓铡俐,卻偏偏與公主長得像凰兑,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子审丘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評(píng)論 2 348

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

  • 從哪說起呢吏够? 單純講多線程編程真的不知道從哪下嘴。。 不如我直接引用一個(gè)最簡(jiǎn)單的問題稿饰,以這個(gè)作為切入點(diǎn)好了 在ma...
    Mr_Baymax閱讀 2,739評(píng)論 1 17
  • GCD GCD簡(jiǎn)介 Grand Central Dispatch中樞調(diào)度器 純C語言的锦秒,提供了非常強(qiáng)大的函數(shù) 優(yōu)勢(shì)...
    彼岸的黑色曼陀羅閱讀 432評(píng)論 0 0
  • 多線程 線程是進(jìn)程內(nèi)部執(zhí)行任務(wù)的一種途徑,多線程技術(shù)能適當(dāng)提高程序執(zhí)行效率和資源利用率喉镰,iOS 中的多線程技術(shù)主要...
    Yasic閱讀 235評(píng)論 0 1
  • 多線程 在iOS開發(fā)中為提高程序的運(yùn)行效率會(huì)將比較耗時(shí)的操作放在子線程中執(zhí)行旅择,iOS系統(tǒng)進(jìn)程默認(rèn)啟動(dòng)一個(gè)主線程,用...
    郭豪豪閱讀 2,590評(píng)論 0 4
  • 在每個(gè)人的一生中都可能會(huì)有一段獨(dú)居的生活。也許是在在北上廣獨(dú)自打拼的日日夜夜捺宗,也許是婚姻圍墻里的精神獨(dú)居柱蟀,也許是步...
    侯七鴨閱讀 696評(píng)論 0 1