在iOS開發(fā)中,當(dāng)遇到網(wǎng)絡(luò)請(qǐng)求和耗時(shí)操作通常需要另外開一個(gè)子線程,然后需要刷新UI的時(shí)候回到主線程刷新;這里就要用到多線程的技術(shù),iOS多線程通常有四種方式:PThread,NSThread,NSOperation,GCD;在這里主要介紹一下GCD的情況下死鎖的幾種情況,以及簡(jiǎn)單的分析:
注:很多資料來自前輩的文章。
1、進(jìn)程和線程的概念:
正在進(jìn)行中的程序被稱為進(jìn)程,負(fù)責(zé)程序運(yùn)行的內(nèi)存分配,每一個(gè)進(jìn)程都有自己獨(dú)立的虛擬內(nèi)存空間。
線程是進(jìn)程中一個(gè)獨(dú)立的執(zhí)行路徑,即主線程,主線程有1M的棧區(qū),對(duì)于耗時(shí)的執(zhí)行路徑,可以放在子線程(512K棧區(qū))中執(zhí)行。
新建線程會(huì)消耗內(nèi)存空間和CPU事件,線程太多會(huì)降低系統(tǒng)的運(yùn)行性能,多線程是通過CPU時(shí)分復(fù)用實(shí)現(xiàn)的。
多線程是為了并發(fā)執(zhí)行多項(xiàng)任務(wù),不會(huì)提高單個(gè)算法本身的執(zhí)行效率。
2、同步和異步
同步就是順序執(zhí)行,執(zhí)行完一個(gè)再執(zhí)行下一個(gè),需要等待、協(xié)調(diào)運(yùn)行。異步就是彼此獨(dú)立,在等待某事件的過程中繼續(xù)做自己的事,不需要等待這一事件完成后再工作。線程就是實(shí)現(xiàn)異步的一個(gè)方式。異步是讓調(diào)用方法的主線程不需要同步等待另一線程的完成,從而可以讓主線程干其它的事情。
異步和多線程并不是一個(gè)同等關(guān)系,異步是最終目的,多線程只是我們實(shí)現(xiàn)異步的一種手段。異步是當(dāng)一個(gè)調(diào)用請(qǐng)求發(fā)送給被調(diào)用者,而調(diào)用者不用等待其結(jié)果的返回而可以做其它的事情。實(shí)現(xiàn)異步可以采用多線程技術(shù)或則交給另外的進(jìn)程來處理。
3、串行和并行
你可以創(chuàng)建任意個(gè)數(shù)的串行隊(duì)列,每個(gè)隊(duì)列依次執(zhí)行添加的任務(wù),一個(gè)隊(duì)列同一時(shí)刻只能執(zhí)行一個(gè)任務(wù)(串行),但是各個(gè)隊(duì)列之間不影響,可以并發(fā)執(zhí)行。每個(gè)隊(duì)列中的任務(wù)運(yùn)行在一個(gè)由各自串行隊(duì)列維護(hù)的獨(dú)立線程上,一個(gè)隊(duì)列中只有一個(gè)線程。
并行隊(duì)列是不允許自己創(chuàng)建的,系統(tǒng)中存在三個(gè)不同優(yōu)先級(jí)的并行隊(duì)列。并行隊(duì)列依舊按照任務(wù)添加的順序啟動(dòng)任務(wù),但是,后一個(gè)任務(wù)無須等待前一個(gè)任務(wù)執(zhí)行完畢,而是啟動(dòng)第一個(gè)任務(wù)后,立即啟動(dòng)下一個(gè)任務(wù)。至于同一時(shí)刻允許同時(shí)運(yùn)行多少個(gè)任務(wù)有系統(tǒng)決定。任務(wù)各自運(yùn)行在并行隊(duì)列為他們提供的獨(dú)立線程上,并行隊(duì)列中同時(shí)運(yùn)行多少個(gè)任務(wù),就必須維護(hù)多少個(gè)線程。
上面講解了關(guān)于GCD的一些基本的概念,接著我們舉幾個(gè)GCD死鎖的案例:
案例一:當(dāng)同步遇到了串行
NSLog(@"1");//任務(wù)1dispatch_sync(dispatch_get_main_queue(), ^{NSLog(@"2");//任務(wù)2});NSLog(@"3");//任務(wù)3
控制臺(tái)輸出結(jié)果:
2017-02-2310:21:00.858GCDTest[1462:51203]1
分析:
dispatch_sync是一個(gè)同步線程;
dispatch_get_main_queue()表示運(yùn)行在主線程中的主隊(duì)列;
任務(wù)二是同步線程的任務(wù)。
任務(wù)三需要等待任務(wù)二結(jié)束之后再執(zhí)行。
分析:首先會(huì)執(zhí)行任務(wù)1毫無疑問,然后程序遇到了同步線程,任務(wù)三要等待同步線程執(zhí)行完再執(zhí)行,而主線程是一個(gè)特殊的串行對(duì)了。遵循FIFO原則來執(zhí)行任務(wù),然后任務(wù)二被加在任務(wù)三的后面要等待任務(wù)三完成才執(zhí)行,這樣就進(jìn)入了互相等待的局面。
案例二:當(dāng)同步遇到了并行
NSLog(@"1");//任務(wù)1dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0), ^{? ? ? ? NSLog(@"2");//任務(wù)2});NSLog(@"3");//任務(wù)3
控制臺(tái)輸出結(jié)果:
2017-02-2310:31:51.647GCDTest[1488:56267]12017-02-2310:31:51.648GCDTest[1488:56267]22017-02-2310:31:51.648GCDTest[1488:56267]3
分析:
毫無疑問首先執(zhí)行任務(wù)一,然后遇到了同步線程,任務(wù)三要等待同步線程執(zhí)行完再執(zhí)行,然后任務(wù)二被加在了子線程,在子線程執(zhí)行完任務(wù)二然后回到主線程繼續(xù)執(zhí)行任務(wù)三。
案例三:同步異步都有
dispatch_queue_tqueue = dispatch_queue_create("com.GCD.serial", DISPATCH_QUEUE_SERIAL);NSLog(@"1");//任務(wù)1dispatch_async(queue, ^{NSLog(@"2");//任務(wù)2dispatch_sync(queue, ^{NSLog(@"3");//任務(wù)3});NSLog(@"4");//任務(wù)4});NSLog(@"5");//任務(wù)5
控制臺(tái)輸出結(jié)果:
2017-02-2310:47:23.876GCDTest[1510:63863]12017-02-2310:47:23.877GCDTest[1510:63863]52017-02-2310:47:23.877GCDTest[1510:63901]2//2和5的輸出順序不一定,3,4沒有輸出
分析:
首先,執(zhí)行任務(wù)一,毫無疑問,然后遇到異步線程操作,任務(wù)5不必等一步線程操作完再執(zhí)行,所以任務(wù)2和任務(wù)5執(zhí)行先后不一定,二異步操作dispatch_async(queue, ^{})中是串行隊(duì)列操作DISPATCH_QUEUE_SERIAL,任務(wù)二和任務(wù)四與任務(wù)三依次執(zhí)行,而任務(wù)三在同步隊(duì)列中,任務(wù)四又要等任務(wù)三執(zhí)行完再執(zhí)行,這樣就造成了任務(wù)三和任務(wù)四互相等待的結(jié)局,死鎖。
案例四:異步遇到同步回主線程
NSLog(@"1");//任務(wù)1dispatch_async(dispatch_get_global_queue(0,0), ^{NSLog(@"2");//任務(wù)2dispatch_sync(dispatch_get_main_queue(), ^{NSLog(@"3");//任務(wù)3});NSLog(@"4");//任務(wù)4});NSLog(@"5");//任務(wù)5
控制臺(tái)輸出結(jié)果:
2017-02-2311:08:01.142GCDTest[1562:72662]12017-02-2311:08:01.143GCDTest[1562:72662]52017-02-2311:08:01.143GCDTest[1562:72712]22017-02-2311:08:01.149GCDTest[1562:72662]32017-02-2311:08:01.149GCDTest[1562:72712]4
分析:
顯然,首先執(zhí)行任務(wù)1,然后遇到異步全局隊(duì)列,所以異步隊(duì)列和任務(wù)5同時(shí)執(zhí)行,不分先后,然后異步隊(duì)列中先執(zhí)行任務(wù)2,遇到同步主隊(duì)列,任務(wù)4要等任務(wù)3完成之后執(zhí)行,而任務(wù)3和任務(wù)4四不在一個(gè)隊(duì)列里,所以任務(wù)3不必等待任務(wù)4的完成。所以,整個(gè)案例的執(zhí)行結(jié)果是:15234或者12534。
案例5:主線程上出現(xiàn)無限循環(huán):
dispatch_async(dispatch_get_global_queue(0,0), ^{NSLog(@"1");//任務(wù)1dispatch_sync(dispatch_get_main_queue(), ^{NSLog(@"2");//任務(wù)2});NSLog(@"3");//任務(wù)3});NSLog(@"4");//任務(wù)4while(1) {? ? }NSLog(@"5");//任務(wù)5
控制臺(tái)輸出結(jié)果:
2017-02-2311:23:36.925GCDTest[1584:78484]12017-02-2311:23:36.925GCDTest[1584:78447]4//或者1 4
分析:
首先是異步線程,任務(wù)4不用等待任務(wù)1的執(zhí)行,同時(shí)執(zhí)行,所以任務(wù)1和任務(wù)4肯定能執(zhí)行到,順序不一定,然后任務(wù)4之后遇到死循環(huán)不再往下執(zhí)行任務(wù)5,而異步隊(duì)列中任務(wù)2又被加入了串行主隊(duì)列任務(wù)5的后面,所以任務(wù)2也不會(huì)執(zhí)行,而任務(wù)1在之前之后遇到同步操作,任務(wù)3要等待任務(wù)2結(jié)束后再執(zhí)行,所以任務(wù)3也不會(huì)執(zhí)行,因此最后結(jié)果是1 4或者4 1。
總結(jié):暫時(shí)能找到的死鎖的情況主要就這幾種,如果文章中有不準(zhǔn)確的地方還望指正,或者有可以補(bǔ)充的地方也希望提出來,本人小白一枚,互相學(xué)習(xí)。