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