




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、GCD 多線程API編程筆記GCD 是 iOS 編程中實現多線程的常用 API,使用方便,無須進行線程的管理,由系統(tǒng)代勞。同時GCD基于C實現,性能強。 在名著Pro multithreading and memory management for iOS and OS X(中文名:Objective-C 高級編程 iOS與 OSX多線程和內存管理)中,專門有章節(jié)講解,特根據此書講解做些筆記。一 概要GCD是Grand Central Dispatch(GCD)的縮寫,是異步執(zhí)行任務的技術之一。一般將應用程序中記述的線程管理用的代碼在系統(tǒng)級中實現。開發(fā)者只需定義想執(zhí)行的任務,然后加入適當的 D
2、ispatch Queue 中,GCD 就能生成相應的線程并計劃執(zhí)行任務。 由于線程管理是系統(tǒng)來實現的,因此可以統(tǒng)一管理,也可執(zhí)行任務,這樣就比之前的線程更有效率。二 API 詳解1. Dispatch Queue“Dispatch Queue” 是執(zhí)行處理的等待隊列。應用程序編程通過 dispatch_async函數等 API,在 Block 語法中記述想執(zhí)行的處理,并將其追加到 Dispatch Queue 中。 Dispatch Queue 按照追加的順序 (先進先出FIFO,First In Firs Out)執(zhí)行處理。 根據處理的策略,分為兩種Dispatch Queue, 一種是等
3、待現在執(zhí)行中處理的Serial Dispatch Queue;另外一種是不等待現在執(zhí)行任務隊列處理的 Concurrent Dispatch Queue。 比較Dispatch Queue的種類如下:Dispatch Queue的種類種類名稱 執(zhí)行情況 Serial Dispatch Queue等待現在執(zhí)行中處理結束 Concurrent Dispatch Queue.不等待現在執(zhí)行處理結束準備以下源代碼,在dispatch_async中追加多個處理。/ Demo code 1dispatch_async(queue, blk0);dispatch_async(queue, blk1);dis
4、patch_async(queue, blk2);dispatch_async(queue, blk3);dispatch_async(queue, blk4);dispatch_async(queue, blk5);dispatch_async(queue, blk6);dispatch_async(queue, blk7);當變量queue為Serial Dispatch Queue 時,因為要等待現在執(zhí)行中的處理結束,所以首先執(zhí)行任務 blk0 ,待 blk0 執(zhí)行結束后,接著執(zhí)行 blk1, blk1 結束后再開始執(zhí)行 blk2,如此重復。同時執(zhí)行的任務只能為1個。即執(zhí)行源代碼片段De
5、mo code 1后,按照以下順序進行處理。blk0blk1blk2blk3blk4blk5blk6blk7但當變量 queue 為 Concurrent Dispatch Queue 時,因為不用等待現在執(zhí)行中的處理結束,所以執(zhí)行順序將變成: 首先執(zhí)行 blk0, 不管 blk0 的執(zhí)行是否結束,都開始執(zhí)行后面的 blk1, 不管 blk1 的執(zhí)行是否結束,都開始執(zhí)行后面的 blk2, 如此重復循環(huán)。 這樣雖然不用等待處理結束,可以并行執(zhí)行多個處理,但并行執(zhí)行的處理數量取決于當前系統(tǒng)的狀態(tài)。 即 iOS 和 OS X 基于 Dispatch Queue 中的處理數、CPU 核數及 CPU 負
6、荷等當前系統(tǒng)的狀態(tài)來決定 Concurrent Dispatch Queue 中并行執(zhí)行的處理數。 所謂“并行執(zhí)行”,就是使用多個線程同時執(zhí)行多個處理。 總結來說,Serial Dispatch Queue 使用一個線程;而Concurrent Dispatch Queue 使用的是多個線程。 iOS 和 OS X的核心 XNU 內核決定應當使用的線程數,并只生成所需的線程執(zhí)行處理。另外,當處理結束,應當執(zhí)行的處理數減少時,XNU內核會結束不再需要的線程。 XNU 內核僅使用 Concurrent Dispatch Queue 便可完美地管理并行執(zhí)行多個處理的線程。假設準備4個 Concurr
7、ent Dispatch Queue 使用的線程。首先:blk0 在線程0中開始執(zhí)行,接著blk1在線程1中、blk2在線程2中、blk3在線程3中開始執(zhí)行。線程0中blk0執(zhí)行結束后,開始執(zhí)行blk4,由于線程1中blk1的執(zhí)行沒有結束,因此線程數中blk2執(zhí)行結束后開始執(zhí)行blk5,就這樣循環(huán)往復。Concurrent Dispatch Queue 執(zhí)行示例 thread0 _ thread1 _ hread2 _ hread3 blk0 = blk1 = blk2 = blk3 blk4 = blk5 blk7像這樣在Concurrent Dispatch Queue中執(zhí)行處理時,執(zhí)行順
8、序會根據處理內容和系統(tǒng)狀態(tài)發(fā)生改變。 它不同于執(zhí)行順序固定的 Serial Dispatch Queue。在不能改變執(zhí)行的處理順序或不想并行執(zhí)行多個處理時使用 Serial Dispatch Queue。 那么如何得到這兩種Queue呢?方法有兩種。2. dispatch_queue_create第一種方式是使用GCD的API生成 Dispatch Queue. 通過 dispatch_queue_create 函數可生成 Dispatch Queue。 以下源代碼生成了 Serial Dispatch Queue。dispatch_queuet mySerialDispatchQueue =
9、 dispatch_queue_create("com.example.gcd.MySerialDispatchQueue", NULL);根據蘋果的API函數聲明:/*! * function dispatch_queue_create * * abstract * Creates a new dispatch queue to which blocks may be submitted. * * discussion * Dispatch queues created with the DISPATCH_QUEUE_SERIAL or a NULL attribute
10、* invoke blocks serially in FIFO order. * * Dispatch queues created with the DISPATCH_QUEUE_CONCURRENT attribute may * invoke blocks concurrently (similarly to the global concurrent queues, but * potentially with more overhead), and support barrier blocks submitted with * the dispatch barrier API, w
11、hich e.g. enables the implementation of efficient * reader-writer schemes. * * When a dispatch queue is no longer needed, it should be released with * dispatch_release(). Note that any pending blocks submitted to a queue will * hold a reference to that queue. Therefore a queue will not be deallocate
12、d * until all pending blocks have finished. * * Passing the result of the dispatch_queue_attr_make_with_qos_class() function * to the attr parameter of this function allows a quality of service class and * relative priority to be specified for the newly created queue. * The quality of service class
13、so specified takes precedence over the quality * of service class of the newly created dispatch queue's target queue (if any) * as long that does not result in a lower QOS class and relative priority. * * When no quality of service class is specified, the target queue of a newly * created dispat
14、ch queue is the default priority global concurrent queue. * * param label * A string label to attach to the queue. * This parameter is optional and may be NULL. * * param attr * DISPATCH_QUEUE_SERIAL, DISPATCH_QUEUE_CONCURRENT, or the result of a call to * the function dispatch_queue_attr_make_with_
15、qos_class(). * * result * The newly created dispatch queue. */_OSX_AVAILABLE_STARTING(_MAC_10_6,_IPHONE_4_0)DISPATCH_EXPORT DISPATCH_MALLOC DISPATCH_RETURNS_RETAINED DISPATCH_WARN_RESULTDISPATCH_NOTHROWdispatch_queue_tdispatch_queue_create(const char *label, dispatch_queue_attr_t attr);dispatch_queu
16、e_create 函數的第一個參數是表示隊列名;第二個參數表示隊列的種類,聲明為NULL表示串行隊列,與參數DISPATCH_QUEUE_SERIAL 同樣的效果表示串行隊列。 關于 Serial Dispatch Queue生成個數的注意事項如下:Serial Dispatch Queue 同時只能執(zhí)行1個追加處理。雖然 Serial Dispatch Queue 和 Concurrent Dispatch Queue 受到系統(tǒng)資源的限制,但用 dispatch_queue_create 函數可生成任意多個 Dispatch Queue。 當生成多個 Serial Dispatch Queu
17、e 時,在每個 Serial Dispatch Queue 中,同時只能執(zhí)行一個追加處理,但各個 Serial Dispatch Queue 將并行執(zhí)行,達到同時執(zhí)行多個任務處理的效果。一旦生成 Serial Dispatch Queue 并追加處理,系統(tǒng)對于一個 Serial Dispatch Queue 就只生成并使用一個線程。 如果生成2000個 Serial Dispatch Queue, 那么就生成2000 個線程。 但是如果使用多線程,就會消耗大量內存,引起大量的上下文切換,大幅度降低系統(tǒng)的響應性能。 只在避免多線程編程問題之一 多個線程更新相同資源導致數據競爭時使用 Serial
18、 Dispatch Queue。 但 Serial Dispatch Queue 的生成個數應當僅限所必需的數量。 例如更新數據庫時1 個表生成1 個 Serial Dispatch Queue,更新文件時1個文件或是可以分割的1個文件塊生成1個 Serial Dispatch Queue. 雖然“Serial Dispatch Queue 比 Concurrent Dispatch Queue 能生成更多的線程”,但絕不能激動之下大量生成 Serial Dispatch Queue。 當想并行執(zhí)行不發(fā)生數據競爭等問題的處理時,使用 Concurrent Dispatch Queue。而且對于
19、Concurrent Dispatch Queue 來說,不管生成多少,由于XNU內核只使用有效管理的線程,因此不會發(fā)生 Serial Dispatch Queue 的那些問題。 繼續(xù)講 dispatch_queue_create 函數。該函數的第一個參數指定 Serial Dispatch Queue 的名稱。像此源代碼這樣, Dispatch Queue 的名稱推薦使用應用程序 ID 這種逆序全程域名(FQDN,fully qualified domain name)。該名稱在 XCode 和Instruments 的調試器中作為 Dispatch Queue 名稱來表示。另外,該名稱也會
20、出現在應用程序崩潰時所生成的 crashLog 中。 我們命名時應遵循這樣的原則:對編程人員和用戶來說都要易懂。如果嫌命名麻煩設為 NULL 也可以,但在調試中一定會后悔沒有為 Dispatch Queue 署名。 生成 Serial Dispatch Queue 時,像該源代碼這樣,將第二個參數指定為NULL。生成Concurrent Dispatch Queue時,像下面源代碼一樣,指定為 DISPATCH_QUEUE_CONCURRENT。dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("co
21、m.example.gcd.MyConcurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT);dispatch_async(myConcurrentDispatchQueue,NSLog("block on myConcurrentDispatchQueue"););并在生成的 Concurrent Dispatch Queue 中執(zhí)行指定的Block。 另外,遺憾的是盡管有ARC這一通過編譯器自動管理內存的優(yōu)秀技術,但生成的Dispatch Queue必須由程序員負責釋放。這是因為Dispatch Queue并沒有像B
22、lock那樣具有作為Objective-C對象來處理的技術。 通過 dispatch_queue_create 函數生成的 Dispatch Queue 在使用結束后通過 dispatch_release 函數釋放。dispatch_release(mySerialDispatchQueue);相應地,也存在dispatch_retain函數。dispatch_retain(myConcurrentDispatchQueue);即Dispatch Queue也像 Objective-C的飲用技術式內存管理一樣,需要通過 dispatch_retain 函數和 dispatch_release
23、函數的引用計數來管理內存。在前面的源代碼中,需要釋放通過 dispatch_queue_create 函數生成并賦值給變量 myConcurrentDispatchQueue 中的 Concurrent Dispatch Queue。 再看一個例子:dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("com.demo.gcd.myConcurrentDispatchQueue",DISPATCH_QUEUE_CONCURRENT);dispatch_async(myConcurrentDis
24、patchQueue,NSLog("block on myConcurrentDispatchQueue"););dispatch_release(myConcurrentDispatchQueue);雖然 Concurrent Dispatch Queue 是使用多線程進行的追加處理,但像該例這樣,在 dispatch_async 函數中追加 Block 到Concurrent Dispatch Queue,并立即通過 dispatch_release函數進行釋放是否可以呢? 該源代碼完全沒有問題。在 dispatch_async 函數中追加 Block 到 Dispat
25、ch Queue ,換言之:該 Block 通過 dispatch_retain 函數持有 Dispatch Queue。無論 Dispatch Queue 是 Serial Dispatch Queue 還是 Concurrent Dispatch Queue 都一樣。一旦Block 執(zhí)行結束,就通過 dispatch_release 函數釋放該 Block 持有的 Dispatch Queue。 也就是說,在 dispatch_async 函數中追加 Block 到 Dispatch Queue 后,即使立即釋放 Dispatch Queue,該 Dispatch Queue 由于被 Bl
26、ock 所持有也不會被廢棄,因而 Block 能夠執(zhí)行。 Block 執(zhí)行結束后會釋放 Dispatch Queue,這時誰都不持有 Dispatch Queue,因此它會被釋放。 另外,能夠使用 dispatch_retain 函數和 dispatch_release 函數的地方不僅是在 Dispatch Queue 中。在之后介紹的幾個 GCD 的 API中,名稱中含有“create”的 API 在不需要其生成的對象時,有必要通過 dispatch_release 函數進行釋放。在通過函數或方法獲取 Dispatch Queue 以及其它名稱中含有 create 的 API 生成的對象時,
27、有必要通過 dispatch_retain 函數持有,并在不需要時通過 dispatch_release 函數釋放。3. Main Dispatch Queue / Global Dispatch Queue第二種方法是獲取系統(tǒng)標準提供的Dispatch Queue。 實際上不用特意生成 Dispatch Queue 系統(tǒng)也會給我們提供幾個。那就是 Main Dispatch Queue 和 Global Dispatch Queue。 3.1 Main Dispatch Queue 主線程中執(zhí)行的 Dispatch Queue,因為主線程只有一個,所以 Main Dispatch Queue
28、 自然就是 Serial Dispatch Queue。 追加到 Main Dispatch Queue 中的任務在主線程的 RunLoop 中執(zhí)行。由于在主線程中執(zhí)行,因此將用戶界面更新等一些必須在主線程中執(zhí)行的處理追加到 Main Dispatch Queue 中使用。這正好和 NSObject 類的 performSelectorOnMainThread 實例方法相同。 3.2 Global Dispatch Queue 所有程序都可以使用,沒有必要通過 dispatch_、queue_create 函數逐個生成 Concurrent Dispatch Queue 。只要獲取 Globa
29、l Dispatch Queue 即可。 Global Dispatch Queue 具有4個優(yōu)先級,分別是: 1)高優(yōu)先級 (High Priority) 2) 默認優(yōu)先級(Default Priority) 3) 低優(yōu)先級(Low Priority) 4) 后臺優(yōu)先級 (Background Priority). 通過 XNU 內核管理的用于 Global Dispatch Queue 的線程,將各自使用的 Global Dispatch Queue 的執(zhí)行優(yōu)先級作為線程的優(yōu)先級來使用。在向 Global Dispatch Queue 追加處理時,應選擇與處理內容執(zhí)行優(yōu)先級一致的 Glob
30、al Dispatch Queue。 但是通過XNU內核用于 Global Dispatch Queue 的線程并不能保證實時性,因此執(zhí)行優(yōu)先級只是大致的判斷。例如在處理內容的執(zhí)行可有可無時,使用后臺優(yōu)先級的 Global Dispatch Queue 等,只能進行這種程度的劃分。系統(tǒng)提供的 Dispatch Queue 總結如下表: Dispatch Queue 的種類 名稱種類說明 Main Dispatch QueueSerial Dispatch Queue主線程執(zhí)行 Global Dispatch Queue(High Priority)Concurrent Dispatch Que
31、ue-執(zhí)行優(yōu)先級:高 Global Dispatch Queue(Default Priority)Concurrent Dispatch Queue-執(zhí)行優(yōu)先級:默認 Global Dispatch Queue(Low Priority)Concurrent Dispatch Queue-執(zhí)行優(yōu)先級:低 Global Dispatch Queue(Background Priority)Concurrent Dispatch Queue-執(zhí)行優(yōu)先級:后臺 各種 Dispatch Queue 的獲取方法如下:/Main Dispatch Queue的獲取方法dispatch_queue_t m
32、ainDispatchQueue = dispatch_get_main_queue();/Global Dispatch Queue(高優(yōu)先級)的獲取方法dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY,0);/Global Dispatch Queue(默認優(yōu)先級)的獲取方法dispatch_queue_t globalDispatchQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIOR
33、ITY_DEFAULT,0);/Global Dispatch Queue(低優(yōu)先級)的獲取方法dispatch_queue_t globalDispatchQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0);/Global Dispatch Queue(后臺優(yōu)先級)的獲取方法dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0);對于Main
34、 Dispatch Queue和 Global Dispatch Queue執(zhí)行 dispatch_retain 和 dispatch_release 函數不會引起任何變化,也不會有任何問題。這也是獲取并使用 Global Dispatch Queue 比生成、使用、釋放 Concurrent Dispatch Queue輕松的原因。 當然,源代碼上進行類似通過 dispatch_queue_create 函數生成 Dispatch Queue 的處理要更輕松時,可參照引用計數內存管理的思維方式,直接在 Main Dispatch Queue 和 Global Dispatch Queue中執(zhí)
35、行 dispatch_retain 和 dispatch_release 函數。 使用 Main Dispatch Queue 和 Global Dispatch Queue 的源代碼如下:/在默認優(yōu)先級的Global Dispatch Queue中執(zhí)行 Blockdispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), /可并行執(zhí)行的處理 /在 Main Dispatch Queue 中執(zhí)行 Block dispatch_async(dispatch_get_main_queue(), /只能在主
36、線程中進行的處理 /比如:UI操作 ););4. dispatch_set_target_queuedispatch_queue_create 函數生成的 Dispatch Queue 不管是 Serial Dispatch Queue 還是 Concurrent Dispatch Queue, 都使用與默認優(yōu)先級 Global Dispatch Queue 相同執(zhí)行優(yōu)先級的線程。而變更生成的 Dispatch Queue 的執(zhí)行優(yōu)先級要使用 dispatch_set_target_queue 函數。在后臺執(zhí)行動作處理的 Serial Dispatch Queue 的生成方法如下:dispat
37、ch_queue_t mySerialDispatachQueue = dispatch_queue_create("com.example.gcd.MySerialDispatchQueue",NULL);dispatch_queue_t globalDispatachQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0);dispatch_set_target_queue(mySerialDispatchQueue,globalDispatchQueueBackground);指定要
38、變更執(zhí)行優(yōu)先級的 Dispatch Queue 為 dispatch_set_target_queue 函數的第一個參數,第二個參數指定為與要使用的執(zhí)行優(yōu)先級相同優(yōu)先級的 Global Dispatch Queue。前者為待變更的 Dispatch Queue, 后者為指定優(yōu)先級的目標 Dispatch Queue。 第一個參數如果指定系統(tǒng)提供的 Main Dispatch Queue 和 Global Dispatch Queue 則不知道會出現什么狀況,因此這些均不可指定。將 Dispatch Queue 指定為 dispatch_set_target_queue 函數的參數,不僅可以變更
39、 Dispatch Queue的執(zhí)行優(yōu)先級,還可以作為 Dispatch Queue 的執(zhí)行階層。如果在多個 Serial Dispatch Queue 中用 dispatch_set_target_queue 函數指定目標為某一個 Serial Dispatch Queue,那么原先本應并行執(zhí)行的多個 Serial Dispatch Queue,在目標 Serial Dispatch Queue 上只能同時執(zhí)行一個處理。 在必須將不可并行執(zhí)行的處理追加到多個 Serial Dispatch Queue 中時,如果使用 dispatch_set_target_queue 函數將目標指定為某一個
40、 Serial Dispatch Queue,即可防止處理并行執(zhí)行。5. dispatch_after想在指定時間后執(zhí)行處理,可使用 dispatch_after 函數來實現。 在3秒后將指定的 Block 追加到 Main Dispatch Queue 中的源代碼如下:dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull *NSEC_PER_SEC);dispatch_after(time,dispatch_get_main_queue(), NSLog("waited at least 3 seconds.&qu
41、ot;););需要注意()的是:dispatch_after 函數并不是在指定時間后執(zhí)行處理,而只是在指定時間后追加處理到 Dispatch Queue。上述源代碼與在3秒后用 dispatch_async函數追加 Block 到 Main Dispatch Queue 的相同。 因為 Main Dispatch Queue 在主線程的 RunLoop 中執(zhí)行, 所以在比如每隔 1/60 秒執(zhí)行的 RunLoop 中,Block 最快在 3 秒后執(zhí)行,最慢在 (3+1/60)秒后執(zhí)行,并且在 Main Dispatch Queue 中有大量處理任務或主線程的處理本身有延遲時,這個時間會更長。雖
42、然在嚴格的時間要求下使用會出現問題,但在大致想延遲執(zhí)行處理時,該函數非常有效。 另外,第二個參數指定要追加處理的 Dispatch Queue, 第三個參數指定記述要處理的Block。 第一個參數是指定時間用的 dispatch_time_t 類型的值。該值可以使用dispatch_time 或 dispatch_walltime 函數生成。 1)dispatch_time 生成函數 計算相對時間dispatch_time_tdispatch_time(dispatch_time_t when, int64_t delta);中第一個參數when起始的時間開始,到第二個參數delta指定的毫微
43、秒單位時間后的時間。when經常使用的值是之前源代碼中出現的DISPATCH_TIME_NOW這表示現在的時間,即以下源代碼可得到表示從現在開始1秒后的dispatch_time_t 類型的值。dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW,1ull * NSEC_PER_SEC);數值和 NSEC_PER_SEC的乘積得到單位為毫微秒的數值?!皍ll”是C語言的數值字面量,是顯示表明類型時使用的字符串(表示“unsigned long long”)。如果使用 NSEC_PER_MSEC則可以以毫秒為單位計算。以下代碼獲取表示從現在
44、開始150毫秒后時間的值。dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW,150ull * NSEC_PER_MSEC);2) dispatch_walltime 函數由POSIX中使用的 struct timespec 類型的時間得到 dispatch_time_t 類型的值。 用于計算絕對時間。例如在 dispatch_after 函數中想指定 2011 年 11 月 11 日 11 時 11 分 11秒 這一絕對時間的情況,這可作為粗略的鬧鐘功能使用。 struct timespec 類型的時間可以很輕松地通過 NSDate
45、類對象生成。下面是示例代碼:dispatch_time_t getDispatchTimeByDate(NSDate *date) NSTimeInterval interval; double second, subsecond; struct timespec time; dispatch_time_t milestone; interval = date timeIntervalSince1970; subsecond = modf(interval, &second); time.tv_sec = cond; time.tv_nsec = subsecond * NSEC_PE
46、R_SEC; milestone = dispatch_walltime(&time, 0); retuen milestone;其中modf函數是獲取double數值的分數(小數)部分的值,同時將整數部分存儲到第二個參數 second中,參考這個英文網站和這個中文網站的解釋:function: modf (param , &intpart) Break into fractional and integral parts Breaks x into an integral and a fractional part.The integer part is stored in
47、the object pointed by intpart, and the fractional part is returned by the function.Both parts have the same sign as x.6. Dispatch Group在追加到 Dispatch Queue 中的多個處理全部結束后想執(zhí)行結束處理,這種情況會經常出現。 只使用一個 Serial Dispatch Queue 時,只要將想執(zhí)行的處理全部追加到該 Serial Dispatch Queue 中并在最后追加結束處理,即可實現。但在使用 Concurrent Dispatch Queue
48、 時或同時使用多個 Dispatch Queue 時,源代碼就會變得頗為復雜。 在此種情況下可以使用Dispatch Group。比如:追加3個Block到 Global Dispatch Queue, 這些 Block 如果全部執(zhí)行完畢,就會執(zhí)行 Main Dispatch Queue中結束處理用的 Block。dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); disp
49、atch_group_async(group, queue, NSLog("blk0"); ); dispatch_group_async(group, queue, NSLog("blk1"); ); dispatch_group_async(group, queue, NSLog("blk2"); ); dispatch_group_notify(group, dispatch_get_main_queue(), NSLog("done"); ); / dispatch_release(group);經過實際測
50、試:dispatch_release(group);代碼必須注釋掉,因為在ARC環(huán)境下該代碼會報錯: “ARC forbids explicit message send of release”. 該源代碼的執(zhí)行結果如下:blk0blk2blk1done因為向 Global Dispatch Queue 即 Concurrent Dispatch Queue 追加處理, 多個線程并行執(zhí)行,所以追加處理的執(zhí)行順序不定。執(zhí)行時的順序會發(fā)生變化,但是最后輸出 done。 無論向什么樣的 Dispatch Queue 中追加處理,使用 Dispatch Group 都可監(jiān)視這些處理執(zhí)行的結束。一旦檢測
51、到所有處理執(zhí)行結束,就可將結束的處理追加到 Dispatch Queue 中。這就是使用 Dispatch Group 的原因。 首先 dispatch_group_create 函數生成 dispatch_group_t 類型的Dispatch Group。如 dispatch_group_create 函數名中所含的 create所示,該 Dispatch Group 與 Dispatch Queue 相同,在使用結束后需要通過 dispatch_release 函數釋放(在ARC模式下不用)。 另外,與追加Block到 Dispatch Queue 時同樣,Block通過 dispatc
52、h_retain 函數持有 Dispatch Group,從而使得該 Block 屬于 Dispatch Group。這樣如果 Block 執(zhí)行結束,該 Block 就通過dispatch_release 函數釋放持有的 Dispatch Group。 一旦 Dispatch Group 使用結束,不用考慮屬于該 Dispatch Group 的 Block,立即通過 dispatch_release 函數釋放即可。 在追加到 Dispatch Group 中的處理全部執(zhí)行結束時,該源代碼中使用的 dispatch_group_notify 函數會將執(zhí)行的 block 追加到 queue中,將
53、第一個參數指定為要監(jiān)視的 group。在追加到該 Dispatch Group 的全部處理執(zhí)行結束時,將第三個參數的 block 追加到第二個參數的 queue(Dispatch Queue)中。在 dispatch_group_notify函數中不管指定什么樣的 Dispatch Queue,屬于 Dispatch Group的全部處理在追加指定的 Block 時都已執(zhí)行結束。 函數原型為:dispatch_group_notify(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);另外,在 Dis
54、patch Group 中也可以使用 dispatch_group_wait 函數等待全部處理執(zhí)行結束。dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, queue, NSLog("blk0"); ); dispatch_group_async(group, queue, NSLog("
55、blk1"); ); dispatch_group_async(group, queue, NSLog("blk2"); ); dispatch_group_wait(group, DISPATCH_TIME_FOREVER);dispatch_group_wait 的函數原型為:/*! * function dispatch_group_wait * * abstract * Wait synchronously until all the blocks associated with a group have * completed or until the
56、specified timeout has elapsed. * * discussion * This function waits for the completion of the blocks associated with the * given dispatch group, and returns after all blocks have completed or when * the specified timeout has elapsed. When a timeout occurs, the group is * restored to its original state. * * This function will return immediately if there are no blocks associated * with the dispatch group (i.e. the group is empty). * * The result of calling this function from multiple threads simultaneous
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- T-ZZB 3706-2024 石化行業(yè)用不銹鋼閥門鑄件
- T-ZJCX 0047-2024 浙江省法人數字證書應用接口規(guī)范
- 二零二五年度宅基地占用權轉讓協(xié)議
- 獨立董事聘用合同(二零二五年度)-能源行業(yè)節(jié)能減排
- 2025年度門面買賣合同(含廣告位租賃)
- 二零二五年度音樂作品著作權許可與網絡播放協(xié)議
- 2025年度校外住宿生安全管理及意外傷害賠償協(xié)議
- 2025年度相鄰宅基地邊界爭議解決與宅基地置換協(xié)議
- 二零二五年度拆除工程合同糾紛解決機制合同
- 二零二五年度自然人個人醫(yī)療設備貸款合同生效與還款規(guī)定
- 人工智能教育背景下中小學教師智能教育素養(yǎng)提升路徑研究
- 2024年中級消防員考試題庫
- 必考古詩賞析知識點(九年級下冊)-2025年中考語文一輪復習
- 2024-2025學年人教版八年級物理上學期課后習題答案
- 遼寧省沈陽市大東區(qū)2024年中考化學模擬試題一
- 國能遼寧北票 200MW 風力發(fā)電項目地質災害危險性評估報告
- 江蘇省常州市教育學會2023-2024學年下學期八年級數學考試卷
- DZ∕T 0214-2020 礦產地質勘查規(guī)范 銅、鉛、鋅、銀、鎳、鉬(正式版)
- 2024年瓦斯爆炸事故專項應急演練桌面推演腳本
- 2024年遼寧大連中遠海運川崎船舶工程有限公司招聘筆試參考題庫含答案解析
- 《單層廠房鋼結構》
評論
0/150
提交評論