多線程編程(GCD)

多線程

Mac、iPhone的操作系統OS X、iOS根據用戶的指示啟動應用程序后,首先便將包含在應用程序中的CPU命令列配置到內存中。CPU從應用程序知道的地址開始,一個一個執行CPU命令列。

在OC的if或for語句等控制語句或函數調用的情況下,執行命令列的地址會遠離當前的位置(位置遷移)。但是,由于一個CPU一次只能執行一個命令,不能執行某處分開的并列的兩個命令,因此通過CPU執行的CPU命令列就好比一條無分叉的大道,其執行不會出現分歧。

通過CPU執行的CPU命令列.png

這里所說的“1個CPU執行的CPU命令列為一條無分叉路徑”,即為“線程”

這種無分叉路徑不只1條,存在有多條時即為“多線程”。1個CPU核執行多條不同路徑上的不同命令。

線程

在多線程中執行CPU命令列.png

OS X和iOS的核心XNU內核在發生操作系統事件時(如每隔一定時間,喚起系統調用等情況)會切換執行路徑。例如CPU的寄存器等信息保存到各自路徑專用的內存塊中,從切換目標路徑專用的內存塊中,復原CPU寄存器等信息,繼續執行切換路徑的CPU命令列。這被稱為“上下文切換

由于使用多線程的程序可以在某個線程和其他線程之間反復多次進行上下文切換,因此看上去就好像1個CPU核能夠并列地執行多個線程一樣。而且在具有多個CPU核的情況下,就不是“看上去像”了,而是真的提供了多個CPU核并行執行多個線程的技術。

這種利用多線程編程的技術就被稱為“多線程編程

但是,多線程編程實際上是一種易發生各種問題的編程技術。比如多個線程更新相同資源會導致數據的不一致(數據競爭)、停止等待事件的線程會導致多個線程相互等待(死鎖)、使用太多線程會消耗大量內存等。

多線程編程導致的問題

*多線程技術

多線程簡單來說是指一個進程中開啟多個線程,多個線程并發執行(同時執行,并行)的技術。例如一個進程中開啟三個線程同時執行3個不同任務:

多線程并行操作

*多線程原理

對于單核CPU而言,同一時間只能執行一個線程,只能允許一個線程工作。多線程并發是指在一個進程中開啟了多個線程,CPU在各個線程之間來回調度。當CPU的調度時間足夠快時就產生了多線程并發執行的效果。

*多線程技術的有優點:

1、可以充分利用多核CPU的性能,提供資源的利用率

2、能夠提高程序的運行效率,使程序響應更快。

3、能夠設置不同任務的執行優先級,

*多線程技術的缺點 (數據競爭、死鎖、太多線程導致消耗大量的內存)

1、線程的創建需要CPU的開銷,對線程的管理需要額外的CPU開銷。線程的使用會為系統帶來上下文環境切換帶來額外的負擔。線程越多,CPU在線程調度管理上的開銷就越大,對于移動設備尤甚。

2、線程之間的通信和數據交互復雜。

3、多個線程直接對于資源的使用會導致程序變慢,同時會導致資源的競爭,數據的共享等不安全問題。

。。。

多線程數據安全問題

程不安全:就是不提供數據訪問保護,有可能出現多個線程先后更改數據造成所得到的數據是臟數據。當多個線程訪問同一塊資源時,很容易引發數據錯亂和數據安全問題。

線程不安全


線程安全:簡單來說就是多個線程同時對共享資源進行訪問時,采用了加鎖機制,當一個線程訪問共享資源,對該資源進行保護,其他線程不能進行訪問直到該線程讀取完,其他線程才可使用。

線程安全

**線程的幾種存在狀態

線程幾種狀態的切換

新建狀態(New):當新創建一個線程時,此時線程處在新建狀態。程序還沒有開始執行線程中的代碼。

就緒狀態(Runnable):一個新創建的線程并不自動開始運行,要執行線程,必須調用線程的start方法創建線程運行的系統資源,這時候線程就處于就緒狀態。

運行狀態(Running):當線程獲得CPU時間后,它才進入運行狀態,真正開始執行線程中的代碼。

阻塞狀態(Blocked):當線程在運行中遇到:1,調用sleep方法;2,線程調用一個在I/O上被阻塞的操作;3,線程等待同步鎖;4,線程在等待某個觸發條件等幾種情況時,線程就處于阻塞狀態。 所謂阻塞狀態是正在運行的線程沒有運行結束,但是不被CPU調度,暫時讓出CPU資源,這時其他處于就緒狀態的線程就可以獲得CPU調度,進入運行狀態。

死亡狀態(Dead): ** 當線程任務執行完畢或者異常時,線程處于死亡狀態。死亡后的線程將不能在執行任務。

iOS中多線程編程的實現方案有一下幾種:pthreadNSThreadGCDNSOperation。


GCD

Grand Central Dispatch(牛逼的中樞調度系統),蘋果公司利用C語言開發的多線程實現技術,旨在通過充分利用設備的多核處理器以優化提升應用程序的運行。

GCD的使用步驟:

創建任務

將任務存放到隊列中(GCD根據隊列的FIFO原則自動將隊列中的任務取出,放到對應的線程中執行)

GCD中三個重要的概念:

任務,就是需要執行的操作;

隊列,就是存放任務的容器,其中隊列又被分為并發隊列、串行隊列兩種。

同步函數/異步函數

GCD中隊列和函數:

并發隊列(Concurrent Dispatch Queue)

允許多個任務并發(同時)執行的隊列

//創建一個并發隊列,標志為? www.cqut.queue

dispatch_queue_t queue = dispatch_queue_create("concurrent.queue", DISPATCH_QUEUE_CONCURRENT);

串行隊列(Serial? Dispatch Queue)

串行隊列中的任務只能依次執行

//創建一個串行隊列,標志為? serial.queue

dispatch_queue_t queue = dispatch_queue_create("serial.queue", DISPATCH_QUEUE_SERIAL);

同步函數

在當前線程執行任務,不會開啟新的線程

//同步函數,傳入隊列,執行Block中的任務

dispatch_sync(dispatch_queue_t? _Nonnull queue, ^(void)block)

異步函數

可以開啟新線程并在其中執行任務

//異步函數,傳入隊列,執行Block中的任務

dispatch_async(dispatch_queue_t? _Nonnull queue, ^(void)block)

注意:同步/異步決定是否開啟線程;并發/串行決定任務的執行方式,允不允許并發。根據函數同步/異步調用和任務放置在并發還是串行隊列中我們可以得到下面四種組合:

異步函數 + 并發隊列

開啟多個子線程同時執行多個任務(任務并行)。

異步函數 + 串行隊列

開啟一個子線程,任務在該線程中依次執行(任務串行)。

同步函數 + 并發隊列

不會開啟子線程,此時的隊列由于沒有子線程支持,失去了并發的能力,任務在當前線程中依次執行(任務串行)。

同步函數 + 串行隊列

不會開啟子線程,任務在隊列中依次執行(任務串行)。

GCD中兩個特殊的隊列:

dispatch_get_main_queue():主隊列

GCD默認創建,只需要使用。該函數返回綁定到主線程的默認串行隊列。該隊列中執行的任務必定是在主線程中執行的。

dispatch_get_global_queue(long identifier, unsigned long flags):全局并發隊列

【參數說明】flags:保留在未來使用,默認傳0;

identifier: 分配到隊列的項目運行的優先級,優先級由高到低依次為:DISPATCH_QUEUE_PRIORITY_HIGH、DISPATCH_QUEUE_PRIORITY_DEFAULT、DISPATCH_QUEUE_PRIORITY_LOW、DISPATCH_QUEUE_PRIORITY_BACKGROUND,一般我們使用默認的DISPATCH_QUEUE_PRIORITY_DEFAULT就能滿足需求

該函數返回

下面一張圖簡單概括一下關于同步/異步函數和各種隊列之間排列組合子線程開啟于任務執行情況:

隊列與線程.png

由圖可知開發中最常用的就是異步函數組合并發和串行隊列,

注意】:使用同步函數(sync)向當前串行隊列中添加任務會卡住當前隊列,導致任務不能正常執行。

GCD中常用的函數

dispatch_barrier_async:在該函數之前的任務必定先執行,在該函數之后的任務后執行(當前隊列不能是全局并發隊列)。

-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {

//并發隊列

dispatch_queue_tqueue =dispatch_queue_create("queue",DISPATCH_QUEUE_CONCURRENT);

//執行下面的異步函數

dispatch_async(queue, ^{

NSLog(@"==1==%@",[NSThreadcurrentThread]);

});

dispatch_barrier_async(queue, ^{

NSLog(@"==barrier==%@",[NSThreadcurrentThread]);

});

dispatch_async(queue, ^{

NSLog(@"==2==%@",[NSThreadcurrentThread]);

});

}

//延時執行

//在主隊列的delayInSeconds秒后執行任務

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

});

//一次性代碼執行

//Block中的代碼保證在程序運行中只執行一次,默認是線程安全的

staticdispatch_once_tonceToken;

dispatch_once(&onceToken, ^{

NSLog(@"onceToken");

});

快速迭代(遍歷)

//全局并發隊列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

//快速遍歷

dispatch_apply(10, queue, ^(size_t index) {

NSLog(@"-%zd-%@",index,[NSThread currentThread]);

});

隊列組

//創建隊列組

dispatch_group_t group = dispatch_group_create();

//全局并發隊列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

//執行任務一

dispatch_group_async(group, queue, ^{

NSLog(@"任務一");

});

//執行任務二

dispatch_group_async(group, queue, ^{

NSLog(@"任務一");

});

//任務一和任務二執行完畢后在打印結果

dispatch_group_notify(group, queue, ^{

NSLog(@"結果");

});

說明:將異步執行的任務一和任務二放到隊列組中,兩個完成執行后再執行打印結果的代碼。


資源鏈接鏈接:http://www.lxweimin.com/p/8a7ebecc06f8

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,412評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,514評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,373評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,975評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,743評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,199評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,262評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,414評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,951評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,780評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,527評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,218評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,649評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,889評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,673評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,967評論 2 374