理理iOS的多線程解決方案 - GCD

周末梳理了一下iOS幾種多線程的方案,總結下平時GCD的主要用法和場景。

一、iOS常見的多線程方案

(1) Pthreads: 基于C語言的框架,在多種操作系統(tǒng)上都有使用,要手動地去管理生命周期,所以在iOS平常的開發(fā)中并不常用。

(2) NSThread: Apple封裝后的線程對象,常用的幾種簡單的獲取線程,啟動取消線程等方法。開發(fā)中只有一些簡單的場景例如[NSThread currentThread], performSelectorOnMainThread:才會使用,因為它在解決問題時還不夠智能,要手動地去管理狀態(tài)。

(3) GCD: Apple為并行計算提出的解決方案,優(yōu)點在于它會自動管理線程的生命周期。同時它使用了Block來讓使用更加方便。

(4) NSOperation & NSOperationQueue: Apple對GCD進行了更多一層的封裝,提供了更多的接口來進行任務的管理。

二、GCD

(1) GCD中兩個重要的基本概念:隊列和任務

* 隊列:

一種遵循FIFO來存放任務的隊列,GCD中有兩種類型:串行隊列(Serial)和并行隊列(Concurrent)

串行隊列:對應一個線程,讓任務一個接一個地執(zhí)行。系統(tǒng)默認提供main_queue,并規(guī)定UI只能在主線程中操作,避免產(chǎn)生混亂

并行隊列:可能對應多個線程,可以讓多個任務同時執(zhí)行。系統(tǒng)默認提供global_queue

我們自己可以創(chuàng)建串行和并行隊列

* 任務:

就是需要執(zhí)行的一段代碼,GCD是放在Block里的。執(zhí)行任務有兩種方式同步執(zhí)行(async)和異步執(zhí)行(async)

如果是同步執(zhí)行,當前任務會阻塞當前線程并等待Block中的任務執(zhí)行完成才繼續(xù)下一個任務

如果是異步執(zhí)行,當前任務不會阻塞等待,會直接往下執(zhí)行。

"放到并行隊列的異步(async)任務,GCD 也會?FIFO的取出來,但不同的是,它取出來一個就會放到別的線程,然后再取出來一個又放到另一個的線程。"

例1:阻塞主線程

分析:這里在主線程發(fā)起了一個主線程中的同步任務,當要開始執(zhí)行的時候,dispatch_sync阻塞了主線程,并嘗試把block中的任務放到主線程中執(zhí)行,但這時候主線程已經(jīng)被阻塞,所以任務無法完成,造成死鎖。

同理:

例2:asyn和async的任務決定了什么?

從以上的結果看來,queue只是管理任務的一個方式,無法決定執(zhí)行的某一個線程,但是能決定任務順序以及是否開辟新的線程。

(2) GCD常用的幾個并行隊列中線程同步的方法:Group、Barrier、Semaphore

dispatch_barrier_async/sync

在GCD中起到一個柵欄的作用,同Concurrent Dispatch Queue隊列一起使用。它等待所有位于barrier函數(shù)之前的操作執(zhí)行完畢后執(zhí)行,并且在barrier函數(shù)執(zhí)行之后,barrier函數(shù)之后的操作才會得到執(zhí)行。

barrier的async和sync的區(qū)別只是,是否在執(zhí)行結束才插入別的任務。但是都會保證同時這個隊列只有這個任務在執(zhí)行

假設有一塊資源需要同步讀異步寫,則可以使用barrier函數(shù)來保證寫操作之前的讀操作全部完成后,才進行寫。不會有兩次讀取的值不一樣的問題。

dispatch_group

可以把任務分組,打包成為一個大的任務,dispatch_group_notify來保證前面的異步/同步任務都結束后才回到某個線程。但是無法保證其中異步任務執(zhí)行的順序

dispatch_semaphore

有時候線程過多,需要控制Concurrent Queue中運行的線程數(shù)量,就可以使用semaphore。而以下的這些在Serial Queue中是不生效的,因為Serial Queue中始終一次只能執(zhí)行一個任務

1. dispatch_semaphore_create?創(chuàng)建一個semaphore

2. dispatch_semaphore_signal?發(fā)送一個信號

3. dispatch_semaphore_wait?等待信號

得出的下面結果看到,semaphore可以控制同時執(zhí)行的線程數(shù)量,換言之也可以用來保證線程的同步。

假設把信號量改成2,則可以看到有兩個任務可以同時進行

用信號量可以實現(xiàn)兩個線程之間的依賴關系

(3)dispatch_once 和?dispatch_after,dispatch_suspend

dispatch_once?

常見的單例創(chuàng)建方法

dispatch_after

dispatch_after是來延遲執(zhí)行的GCD方法,因為在主線程中我們不能用sleep來延遲方法的調(diào)用,所以用dispatch_after是最合適的,dispatch_after的真正含義是在6秒后把任務添加進隊列中,并不是表示在6秒后執(zhí)行。

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2?*?NSEC_PER_SEC)),?dispatch_get_main_queue(), ^{

?NSLog(@"after 2 seconds %@",[NSThread?currentThread]);

?});

dispatch_suspend

suspend不會立即暫停正在運行的block,而是在當前block執(zhí)行完成后,暫停后續(xù)的block執(zhí)行。

(4)線程之間通信

(5)如何停止一個GCD中正在運行的線程

用一個全局變量或是property來控制

@property(nonatomic, assign)BOOL shouldCancel;
@property(nonatomic, strong)dispatch_queue_t conQueue;

-?(void)viewDidAppear:(BOOL)animated? {??

????[super?viewDidAppear:animated];??

????self.conQueue =?dispatch_get_global_queue(0,?0);??

????dispatch_async(self.conQueue,?^{??

????????while?(!self.shouldCancel)?{??

????????????????sleep(1);??

? ? ? ? };??

????});??

}??


-?(void)closeThread? {??

if?(self.conQueue)?{??

????????self.shouldCancel?=?YES;??

????????dispatch_suspend(q);??

????????dispatch_release(q);??

? ? ? ? self.conQueue?=?nil;??

????}??

}??

Reference

http://www.itdecent.cn/p/0b0d9b1f1f19

http://www.itdecent.cn/p/2d57c72016c6

http://www.itdecent.cn/p/cfcc0c302621

http://blog.csdn.net/linfengwenyou/article/details/48948355

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容