GCD多線程編程常用API介紹

什么是GCD?

Grand Central Dispatch(GCD)是蘋果開發(fā)的一項(xiàng)技術(shù),用于提升應(yīng)用在多核處理器上運(yùn)行時(shí)的表現(xiàn),使系統(tǒng)和應(yīng)用更快速、高效的運(yùn)行。和NSThread以及NSOperationQueue相比,GCD能更靈活的滿足應(yīng)用需求,并以更加平衡的方式實(shí)現(xiàn)系統(tǒng)資源調(diào)度。

DISPATCH對(duì)象

Dispatch對(duì)象(dispatch_object_t)是對(duì)多種dispatch類型對(duì)象的統(tǒng)稱,包括dispatch_source_t、dispatch_queue_t、dispatch_group_t、dispatch_semaphore_t等等。
在使用GCD時(shí),我們通過dispatch對(duì)象來實(shí)現(xiàn)對(duì)內(nèi)存、任務(wù)以及任務(wù)隊(duì)列的管理。
在使用OC編程時(shí),所有的dispatch對(duì)象都可以被當(dāng)作OC對(duì)象來對(duì)待。在ARC環(huán)境下,dispatch對(duì)象將被自動(dòng)的引用和釋放;在MRC環(huán)境下,可以通過dispatch_retain()和dispatch_release()函數(shù)來實(shí)現(xiàn)對(duì)dispatch對(duì)象的引用和釋放操作。

DISPATCH QUEUE

  • Dispatch queue(dispatch_queue_t)對(duì)象表示一個(gè)任務(wù)隊(duì)列。任務(wù)隊(duì)列分為串行隊(duì)列和并行隊(duì)列兩種。
  • 一個(gè)串行dispatch queue會(huì)按照FIFO的順序來執(zhí)行提交到該隊(duì)列的任務(wù),并且同一時(shí)間只能執(zhí)行一個(gè)任務(wù)。
  • 一個(gè)并行dispatch queue可以同時(shí)執(zhí)行多個(gè)任務(wù)。
  • 多個(gè)dispatch queue之間是獨(dú)立的,且互不影響的執(zhí)行添加到自己隊(duì)列的任務(wù)。

DISPATCH QUEUE的創(chuàng)建

我們有三種方式獲得一個(gè)dispatch queue對(duì)象:

  • 獲取主線程隊(duì)列
    調(diào)用dispatch_get_main_queue()可以獲取主線程的任務(wù)隊(duì)列。這是一個(gè)串行隊(duì)列。
  • 獲取全局并行隊(duì)列
    調(diào)用dispatch_get_global_queue()可以獲取全局并行隊(duì)列。
  • 創(chuàng)建一個(gè)隊(duì)列
    我們可以通過調(diào)用dispatch_queue_create()來自己創(chuàng)建一個(gè)隊(duì)列。
dispatch_queue_t queue;
    //獲取主線程隊(duì)列
    queue = dispatch_get_main_queue();
    //獲取全局并行隊(duì)列
    queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //創(chuàng)建串行隊(duì)列
    queue = dispatch_queue_create("label", DISPATCH_QUEUE_SERIAL);
    //創(chuàng)建并行隊(duì)列
    queue = dispatch_queue_create("label", DISPATCH_QUEUE_CONCURRENT);

向DISPATCH QUEUE添加任務(wù)

  • 向一個(gè)dispatch queue添加任務(wù)分為同步添加和異步添加兩種。被添加的任務(wù)既可以是一個(gè)block,也可以是一個(gè)函數(shù)。
  • 使用dispatch_sync() 和 dispatch_sync_f() 將任務(wù)同步添加到隊(duì)列中,該函數(shù)直到被添加的任務(wù)執(zhí)行完成后才會(huì)返回。
  • 使用dispatch_async() 和 dispatch_async_f() 將任務(wù)異步添加到隊(duì)列中,該函數(shù)調(diào)用后將會(huì)立即返回,不會(huì)等待被添加的任務(wù)執(zhí)行完成。
void function(void *context) {
    NSNumber *number = (__bridge_transfer NSNumber *)context;
    NSLog(@"number = %@", number);
}
 - (void)main {
    //獲取隊(duì)列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //同步添加一個(gè)block
    dispatch_sync(queue, ^{
        /* code in block... */
    });
    //同步添加一個(gè)函數(shù)
    NSNumber *number100 = @(100);
    dispatch_sync_f(queue, (__bridge_retained void *)number100, function);
    //異步添加一個(gè)block
    dispatch_async(queue, ^{
        /* code in block... */
    });
    //異步添加一個(gè)函數(shù)
    NSNumber *number200 = @(200);
    dispatch_async_f(queue, (__bridge_retained void *)number200, function);
}

DISPATCH SOURCE

Dispatch source對(duì)象(dispatch_source_t)表示一個(gè)事件源,它可以監(jiān)視一個(gè)特定的事件,并在事件發(fā)生時(shí)向指定的隊(duì)列添加指定的任務(wù)。

DISPATCH SOURCE的創(chuàng)建

  • 使用dispatch_source_create()來創(chuàng)建一個(gè)dispatch source對(duì)象。
    該函數(shù)定義如下:
dispatch_source_t dispatch_source_create(
        dispatch_source_type_t type,
        uintptr_t handle,
        unsigned long mask,
        dispatch_queue_t queue);
  • 第一個(gè)參數(shù)為要監(jiān)視的事件類型,第二個(gè)參數(shù)和第三個(gè)參數(shù)需要根據(jù)第一個(gè)參數(shù)中的事件類型來確定,第四個(gè)參數(shù)為事件發(fā)生時(shí)任務(wù)要添加到的隊(duì)列。
//創(chuàng)建dispatch source,事件類型為DISPATCH_SOURCE_TYPE_TIMER
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
//設(shè)定timer的開始時(shí)間,間隔和延時(shí)誤差
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC, 0.00 * NSEC_PER_SEC);
//設(shè)定事件發(fā)生時(shí)向隊(duì)列添加的任務(wù)
dispatch_source_set_event_handler(timer, ^{
     /* code in block */
 });
//開始dispatch source
dispatch_resume(timer);

任務(wù)隊(duì)列的同步

多個(gè)dispatch queue間的同步可以通過多種方式來實(shí)現(xiàn)。GCD原生提供了dispatch semaphore、dispatch group、dispatch barrier等多種方式同步。

DISPATCH SEMAPHONE

  • Dispatch semaphore(信號(hào))通過計(jì)數(shù)的方式實(shí)現(xiàn)多個(gè)線程間的同步,每個(gè)dispatch semaphore對(duì)象都有一個(gè)計(jì)數(shù)值。
  • 調(diào)用dispatch_semaphore_create() 可以創(chuàng)建一個(gè)semaphore對(duì)象。
  • 在一個(gè)線程中調(diào)用dispatch_semaphore_wait()可以使semaphore的計(jì)數(shù)減1。如果semaphore的計(jì)數(shù)在減1后小于0,那么線程進(jìn)入阻塞,直至semaphore的計(jì)數(shù)大于或等于0為止。
  • 調(diào)用dispatch_semaphore_signal()可以使semaphore的計(jì)數(shù)加1。
    //創(chuàng)建一個(gè)dispatch semaphore,參數(shù)為semaphore對(duì)象的初始計(jì)數(shù)值
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    //創(chuàng)建a,b兩個(gè)隊(duì)列
    dispatch_queue_t queue_a = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue_b = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
    //分別向兩個(gè)隊(duì)列添加任務(wù)
    dispatch_async(queue_a, ^{
        NSLog(@"1");
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//由于semaphore初始計(jì)數(shù)為0,調(diào)用dispatch_semaphore_wait后計(jì)數(shù)為-1,隊(duì)列a進(jìn)入阻塞。
        NSLog(@"4");
    });
    dispatch_async(queue_b, ^{
        NSLog(@"2");
        sleep(3);//隊(duì)列b睡眠3秒。
        NSLog(@"3");
        dispatch_semaphore_signal(semaphore);//使semaphore的計(jì)數(shù)加1,加1后semaphore計(jì)數(shù)為0,隊(duì)列a停止阻塞,開始繼續(xù)執(zhí)行。
    });
    //代碼運(yùn)行后立即輸出1、2
    //3s后依次輸出3、4

DISPATCH GROUP

  • Dispatch group通過使用dispatch group對(duì)象來管理多個(gè)隊(duì)列中的多個(gè)任務(wù)。
  • 在創(chuàng)建一個(gè)dispatch group對(duì)象后,可以使用dispatch_group_async() 或者dispatch_group_enter() 將任務(wù)(block或者函數(shù))添加到group。
  • 使用dispatch_group_wait() 來等待group中的所有任務(wù)都執(zhí)行完畢。
  • 使用dispatch_group_notify() 可以使一個(gè)group中的任務(wù)都執(zhí)行完畢后向指定的隊(duì)列發(fā)送通知。
    //創(chuàng)建一個(gè)dispatch group對(duì)象
    dispatch_group_t group = dispatch_group_create();
    //創(chuàng)建一個(gè)串行隊(duì)列和一個(gè)并行隊(duì)列
    dispatch_queue_t queue_a = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue_b = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
    //向group添加block任務(wù),第二個(gè)參數(shù)為執(zhí)行這個(gè)任務(wù)的隊(duì)列
    dispatch_group_async(group, queue_b, ^{
        NSLog(@"0");
        sleep(2);//睡眠2s
        NSLog(@"2");
    });
    //直接向隊(duì)列b添加一個(gè)block任務(wù)
    dispatch_async(queue_b, ^{
        NSLog(@"1");
        dispatch_group_enter(group);//聲明將以下代碼加入到group中去。
        sleep(3);//睡眠3s
        NSLog(@"3");
        dispatch_group_leave(group);//聲明添加到group的代碼在此結(jié)束。
        sleep(2);//睡眠2s
        NSLog(@"6");
    });
    //等待group中的任務(wù)全部完成后,在主線程隊(duì)列執(zhí)行block
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"5");
    });
    dispatch_async(queue_a, ^{
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);//等待group中的任務(wù)完成。
        NSLog(@"4");
    });
    //代碼運(yùn)行后將立即輸出0、1
    //在第二秒的時(shí)候輸出2
    //在第三秒的時(shí)候輸出3、4、5
    //在第五秒的時(shí)候輸出6

DISPATCH BARRIER

  • Dispatch barrier提供了兩個(gè)方法來同步或異步的向一個(gè)隊(duì)列中添加任務(wù)。使用dispatch_barrier_async() 和dispatch_barrier_sync() 來異步和同步的向一個(gè)隊(duì)列中添加任務(wù)。
  • 根據(jù)dispatch barrier可以將一個(gè)隊(duì)列中的任務(wù)分為三部分:在dispatch barrier之前添加的任務(wù)、dispatch barrier添加的任務(wù)(稱為 barrier block)、在dispatch barrier之后添加的任務(wù)。
  • Barrier block將會(huì)等待所有在barrier block之前被添加到隊(duì)列中的任務(wù)都執(zhí)行完畢后才回執(zhí)行。
    在dispatch barrier之后添加到隊(duì)列中的所有任務(wù),將會(huì)一直等待barrier block執(zhí)行完畢后才會(huì)執(zhí)行。
  • Dispatch barrier只對(duì)并行隊(duì)列( DISPATCH_QUEUE_CONCURRENT )有效。
    //創(chuàng)建一個(gè)并行隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
    //向隊(duì)列添加一個(gè)任務(wù)
    dispatch_async(queue, ^{
        NSLog(@"0");
        sleep(3);
        NSLog(@"2");
    });
    //向隊(duì)列添加一個(gè)任務(wù)
    dispatch_async(queue, ^{
        NSLog(@"1");
    });
    //使用dispatch barrier向隊(duì)列添加一個(gè)任務(wù)
    dispatch_barrier_async(queue, ^{
        NSLog(@"3");
        sleep(1);
        NSLog(@"4");
    });
    //向隊(duì)列添加一個(gè)任務(wù)
    dispatch_async(queue, ^{
        NSLog(@"5");
    });
    //代碼運(yùn)行后將立即輸出0、1
    //在第三秒輸出2、3
    //在第四秒輸出4、5
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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