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í),我們通過(guò)dispatch對(duì)象來(lái)實(shí)現(xiàn)對(duì)內(nèi)存蹲坷、任務(wù)以及任務(wù)隊(duì)列的管理驶乾。
在使用OC編程時(shí),所有的dispatch對(duì)象都可以被當(dāng)作OC對(duì)象來(lái)對(duì)待循签。在ARC環(huán)境下级乐,dispatch對(duì)象將被自動(dòng)的引用和釋放;在MRC環(huán)境下县匠,可以通過(guò)dispatch_retain()和dispatch_release()函數(shù)來(lái)實(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的順序來(lái)執(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ì)列
    我們可以通過(guò)調(diào)用dispatch_queue_create()來(lái)自己創(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()來(lái)創(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ù)中的事件類型來(lái)確定扎即,第四個(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間的同步可以通過(guò)多種方式來(lái)實(shí)現(xiàn)。GCD原生提供了dispatch semaphore刁绒、dispatch group闷营、dispatch barrier等多種方式同步。

DISPATCH SEMAPHONE

  • Dispatch semaphore(信號(hào))通過(guò)計(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通過(guò)使用dispatch group對(duì)象來(lái)管理多個(gè)隊(duì)列中的多個(gè)任務(wù)。
  • 在創(chuàng)建一個(gè)dispatch group對(duì)象后莹规,可以使用dispatch_group_async() 或者dispatch_group_enter() 將任務(wù)(block或者函數(shù))添加到group赔蒲。
  • 使用dispatch_group_wait() 來(lái)等待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è)方法來(lái)同步或異步的向一個(gè)隊(duì)列中添加任務(wù)。使用dispatch_barrier_async() 和dispatch_barrier_sync() 來(lái)異步和同步的向一個(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)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市儡陨,隨后出現(xiàn)的幾起案子褪子,更是在濱河造成了極大的恐慌,老刑警劉巖骗村,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嫌褪,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡胚股,警方通過(guò)查閱死者的電腦和手機(jī)笼痛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)琅拌,“玉大人缨伊,你說(shuō)我怎么就攤上這事〔坪觯” “怎么了倘核?”我有些...
    開封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵泣侮,是天一觀的道長(zhǎng)即彪。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么隶校? 我笑而不...
    開封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任漏益,我火速辦了婚禮,結(jié)果婚禮上深胳,老公的妹妹穿的比我還像新娘绰疤。我一直安慰自己,他們只是感情好舞终,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開白布轻庆。 她就那樣靜靜地躺著,像睡著了一般敛劝。 火紅的嫁衣襯著肌膚如雪余爆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天夸盟,我揣著相機(jī)與錄音蛾方,去河邊找鬼。 笑死上陕,一個(gè)胖子當(dāng)著我的面吹牛桩砰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播释簿,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼亚隅,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了辕万?” 一聲冷哼從身側(cè)響起枢步,我...
    開封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎渐尿,沒想到半個(gè)月后醉途,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡砖茸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年隘擎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凉夯。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡货葬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出劲够,到底是詐尸還是另有隱情震桶,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布征绎,位于F島的核電站蹲姐,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜柴墩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一忙厌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧江咳,春花似錦逢净、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至踩身,卻和暖如春着饥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背惰赋。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工宰掉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人赁濒。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓轨奄,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親拒炎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挪拟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 最近頗花了一番功夫把多線程GCD人的一些用法總結(jié)出來(lái),一來(lái)幫自己鞏固一下知識(shí)击你、二來(lái)希望能幫到對(duì)這一塊還迷茫...
    人活一世閱讀 284評(píng)論 1 1
  • 一玉组、前言 上一篇文章iOS多線程淺匯-原理篇中整理了一些有關(guān)多線程的基本概念。本篇博文介紹的是iOS中常用的幾個(gè)多...
    nuclear閱讀 2,047評(píng)論 6 18
  • iOS 多線程系列 -- 基礎(chǔ)概述iOS 多線程系列 -- pthreadiOS 多線程系列 -- NSThrea...
    shannoon閱讀 838評(píng)論 0 2
  • 人類從宇宙中學(xué)到的丁侄,充分印證了Albert Schweitzer那句名言:“我憂心忡忡地看待未來(lái)惯雳,但仍滿懷美好的希...
    dnaEMx閱讀 1,513評(píng)論 1 1
  • 《時(shí)間管理—如何充分利用你的24小時(shí)》作者:吉姆·蘭德爾 1、自我意識(shí)是先決條件 只有當(dāng)你真正意識(shí)到你是如何支配時(shí)...
    清寒泠冽閱讀 135評(píng)論 1 3