GCD的使用

iOS實(shí)際上算是unix的一個(gè)分支,所以iOS上的多線程可以使用pthread。不過Apple另外提供了GCD來簡化多線程編程,實(shí)際上GCD是基于pthread的。大部分情況下使用iOS多線程都是和I/O相關(guān)的,需要記住UI相關(guān)的操作必須是單線程(main thread)的。

在GCD中我們并不是直接創(chuàng)建線程,而是使用queue(隊(duì)列)。GCD中的queue分為兩類:Serial和Concurrent,前者是需要等待前一個(gè)任務(wù)結(jié)束的,后者并不需要(任務(wù)執(zhí)行順序只有上帝才知道)。我們可以使用 dispatch_queue_create函數(shù)創(chuàng)建一個(gè)queue。

//默認(rèn)是Serial
dispatch_queue_create("ax_serial_queue", NULL/*DISPATCH_QUEUE_SERIAL*/);
dispatch_queue_create("ax_concurrent_queue", DISPATCH_QUEUE_CONCURRENT);

也可以直接獲取iOS為我們提供的queue。iOS為我們提供了兩個(gè)queue: ** Main Dispatch Queue ** (主線程)、Global Dispatch Queue,前者是Serial后者是Concurrent。其中Global Dispatch Queue有四種運(yùn)行級(jí)別:high、default、low、background。

dispatch_get_main_queue()
//下面的第二個(gè)參數(shù)一般為0,目前沒有使用這個(gè)參數(shù)。
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

創(chuàng)建/獲取了queue之后就可以向queue中添加任務(wù),常用的是dispatch_async,這個(gè)是異步的,即不等待任務(wù)完成,dispatch_sync是同步的,即等待任務(wù)完成。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^
{
    printf("block 1\n"):
});

直接執(zhí)行上面的代碼很可能會(huì)沒有輸出結(jié)果,:-D主線程已經(jīng)結(jié)束了(可以使用sleep試試)。為了更方便地管理,我們可以使用group。group使用dispatch_group_create()直接創(chuàng)建,然后將上面的dispatch_async改為dispatch_group_async即可。

 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, ^{printf("block1\n");});
 dispatch_group_async(group, queue, ^{printf("block2\n");});
 dispatch_group_async(group, queue, ^{printf("block3\n");});
 dispatch_group_async(group, queue, ^{printf("block4\n");});

 dispatch_group_notify(group, dispatch_get_main_queue(), ^{printf("block done\n");});

 /*也可以試試下面的代碼
 dispatch_group_wait(group,DISPATCH_TIME_FOREVER);
 printf("block done\n");*/

上面的代碼可以等待任務(wù)全部完成并輸出結(jié)果,不過可能會(huì)有點(diǎn)小問題,如果是在主線程中執(zhí)行上面的代碼,block done結(jié)果并沒有看到。這是因?yàn)橹骶€程的queue是Serial的,新任務(wù)要等主線程結(jié)束才會(huì)執(zhí)行。

dispatch_group_notify(group, queue, ^{printf("block done\n");});

修改之后就沒有問題了。dispatch_group_notifydispatch_group_wait函數(shù)的使用就不再過多的說明了。

通常情況下,使用多線程要注意讀寫鎖。讀可以多個(gè)線程一起讀,寫只能一個(gè)線程寫。在多個(gè)dispatch_async中插入dispatch_barrier_async就可以實(shí)現(xiàn)pthread的讀寫鎖的效果。

dispatch_async(concurrent_queue, ^{printf("1\n");});
dispatch_async(concurrent_queue, ^{printf("2\n");});
    
dispatch_barrier_async(concurrent_queue, ^{printf("3\n");});

dispatch_async(concurrent_queue, ^{printf("4\n");});
dispatch_async(concurrent_queue, ^{printf("5\n");});

執(zhí)行順序是1/2 => 3 =>4/5,1和2的順序不定,4和5的順序不定,3必然在1、2之后以及4、5之前。

如何寫一個(gè)線程安全的單列了?這是面試中常問的一個(gè)問題。GCD中使用dispatch_once可以簡單高效的完成這一類任務(wù)。

static dispatch_once_t classA_once;
dispatch_once(&classA_once,^
{
    //initialization
});

GCD中還有諸如Semaphore、I/O的內(nèi)容,不過實(shí)際中這些內(nèi)容使用的比較少,就在此跳過了。使用GCD進(jìn)行多線程編程需要我們注意的就是死鎖,比如在主線程中運(yùn)行dispatch_sync(dispatch_get_main_queue(),^{......});會(huì)直接導(dǎo)致程序crash這樣的嚴(yán)重后果。我們需要慎重地使用dispatch_sync函數(shù),上面group案例中的在dispatch_get_main_queue中使用dispatch_async也沒有想我們想象的一樣執(zhí)行。

如有錯(cuò)誤,歡迎指出!

最后編輯于
?著作權(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)容