iOS之GCD筆記二

隊列的幾種創(chuàng)建方式

  • 串行隊列

dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);

serialQueue:表示隊列的名稱
DISPATCH_QUEUE_SERIAL:表示為串行隊列

dispatch_queue_t nullQueue = dispatch_queue_create("nullQueue", NULL);

后面標(biāo)注的NULL也是串行隊列

dispatch_queue_t mainQueue = dispatch_get_main_queue();

主隊列是一種特殊的串行隊列

  • 并發(fā)隊列

dispatch_queue_t concurrentQueue = dispatch_queue_create("asynQueue", DISPATCH_QUEUE_CONCURRENT);

DISPATCH_QUEUE_CONCURRENT:表示為并發(fā)隊列

dispatch_queue_t highGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);

并發(fā)隊列+優(yōu)先級高

dispatch_queue_t defaultGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    NSLog(@"defaultGlobalQueue-----%@",defaultGlobalQueue);

并發(fā)隊列+優(yōu)先級默認(rèn)

dispatch_queue_t lowGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
    NSLog(@"lowGlobalQueue-----%@",lowGlobalQueue)

并發(fā)隊列+優(yōu)先級低

dispatch_queue_t backGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
    NSLog(@"backGlobalQueue-----%@",backGlobalQueue);

并發(fā)隊列+優(yōu)先級最低

優(yōu)先級高的隊列里的任務(wù)會先執(zhí)行恢暖,之后才執(zhí)行優(yōu)先級低的隊列中的任務(wù)(需要注意:十次里面可能有九次都是等待優(yōu)先級高的隊列里的任務(wù)全部執(zhí)行完畢才開始執(zhí)行優(yōu)先級低的隊列中的任務(wù)下隧,但是也會出現(xiàn)優(yōu)先級高的隊列中的任務(wù)沒有完全執(zhí)行完成就開始執(zhí)行優(yōu)先級低的隊列中的任務(wù))
親測如下(測試很多次才可能出現(xiàn)一次):highGlobalQueue中i=9的那次打印還沒執(zhí)行,lowGlobalQueue中i=0的那次打印就執(zhí)行了

for (int i = 0; i< 10;i++){
        dispatch_async(lowGlobalQueue, ^{
            NSLog(@"backGlobalQueue--%@--%d",[NSThread currentThread], i);
        });
        dispatch_async(highGlobalQueue, ^{
            NSLog(@"lowGlobalQueue--%@--%d",[NSThread currentThread], i);
        });
    }

打印結(jié)果如下

2018-08-22 16:35:50.621567+0800 GCD_Demo[92525:3732297] highGlobalQueue--<NSThread: 0x604000473900>{number = 183, name = (null)}--0
2018-08-22 16:35:50.621647+0800 GCD_Demo[92525:3732204] highGlobalQueue--<NSThread: 0x6040004737c0>{number = 174, name = (null)}--1
2018-08-22 16:35:50.621685+0800 GCD_Demo[92525:3732299] highGlobalQueue--<NSThread: 0x604000472280>{number = 185, name = (null)}--2
2018-08-22 16:35:50.621698+0800 GCD_Demo[92525:3732198] highGlobalQueue--<NSThread: 0x60000027cb80>{number = 169, name = (null)}--3
2018-08-22 16:35:50.621722+0800 GCD_Demo[92525:3732207] highGlobalQueue--<NSThread: 0x604000472a40>{number = 177, name = (null)}--4
2018-08-22 16:35:50.621728+0800 GCD_Demo[92525:3732201] highGlobalQueue--<NSThread: 0x600000275f00>{number = 171, name = (null)}--5
2018-08-22 16:35:50.621738+0800 GCD_Demo[92525:3732203] highGlobalQueue--<NSThread: 0x6040004741c0>{number = 173, name = (null)}--6
2018-08-22 16:35:50.621797+0800 GCD_Demo[92525:3732295] highGlobalQueue--<NSThread: 0x60400046df40>{number = 181, name = (null)}--7
2018-08-22 16:35:50.621817+0800 GCD_Demo[92525:3732296] highGlobalQueue--<NSThread: 0x60400046a100>{number = 182, name = (null)}--9
2018-08-22 16:35:50.621761+0800 GCD_Demo[92525:3732206] lowGlobalQueue--<NSThread: 0x604000470880>{number = 176, name = (null)}--0
2018-08-22 16:35:50.621823+0800 GCD_Demo[92525:3731738] highGlobalQueue--<NSThread: 0x604000473040>{number = 154, name = (null)}--8
2018-08-22 16:35:50.622011+0800 GCD_Demo[92525:3732298] lowGlobalQueue--<NSThread: 0x60400046a300>{number = 184, name = (null)}--1
2018-08-22 16:35:50.622329+0800 GCD_Demo[92525:3732265] lowGlobalQueue--<NSThread: 0x604000473c80>{number = 179, name = (null)}--3
2018-08-22 16:35:50.622349+0800 GCD_Demo[92525:3732294] lowGlobalQueue--<NSThread: 0x604000472c80>{number = 180, name = (null)}--2
2018-08-22 16:35:50.622505+0800 GCD_Demo[92525:3732299] lowGlobalQueue--<NSThread: 0x604000472280>{number = 185, name = (null)}--5
2018-08-22 16:35:50.622406+0800 GCD_Demo[92525:3732204] lowGlobalQueue--<NSThread: 0x6040004737c0>{number = 174, name = (null)}--4
2018-08-22 16:35:50.622536+0800 GCD_Demo[92525:3732198] lowGlobalQueue--<NSThread: 0x60000027cb80>{number = 169, name = (null)}--6
2018-08-22 16:35:50.623330+0800 GCD_Demo[92525:3732207] lowGlobalQueue--<NSThread: 0x604000472a40>{number = 177, name = (null)}--7
2018-08-22 16:35:50.623420+0800 GCD_Demo[92525:3732297] lowGlobalQueue--<NSThread: 0x604000473900>{number = 183, name = (null)}--8
2018-08-22 16:35:50.623996+0800 GCD_Demo[92525:3732295] lowGlobalQueue--<NSThread: 0x60400046df40>{number = 181, name = (null)}--9

GCD的常見用法

  • dispatch_apply

該函數(shù)指定次數(shù)將指定的Block追加到指定的Queue中厢洞,并等待全部處理執(zhí)行結(jié)束

第一個參數(shù)是執(zhí)行的次數(shù)
第二個參數(shù)是任務(wù)加入的隊列
第三個block是執(zhí)行的任務(wù)劝堪,需傳入一個次數(shù)的參數(shù)

dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {
        NSLog(@"dispatch_apply--%@--%ld",[NSThread currentThread], index);
    });
  • dispatch_barrier

GCD柵欄函數(shù):在并發(fā)隊列中將此代碼插入的地方上下隔開,如果柵欄一樣呀闻,兩部分不影響精肃。只有上邊的并發(fā)隊列都執(zhí)行結(jié)束之后秤涩,下邊的并發(fā)隊列才能夠執(zhí)行。

如下例子中:指定在任務(wù)1司抱、2(無序)執(zhí)行之后筐眷,執(zhí)行任務(wù)barrier,然后執(zhí)行任務(wù)3习柠、4(無序)
特點(diǎn):指定在任務(wù)1匀谣、2、3资溃、4是在同一個隊列中執(zhí)行才有效

dispatch_barrier_async與dispatch_barrier_sync區(qū)別:

dispatch_barrier_sync代碼后邊的任務(wù)直到dispatch_barrier_sync執(zhí)行完才能被追加到隊列中武翎;
dispatch_barrier_async不用代碼執(zhí)行完,后邊的任務(wù)也會被追加到隊列中肉拓。
代碼上的體現(xiàn)就是dispatch_barrier_sync后邊的代碼不會執(zhí)行后频,dispatch_barrier_async后邊的代碼會執(zhí)行,但是Block不會被執(zhí)行暖途。

    dispatch_queue_t queue = dispatch_queue_create("testDispatch_barrier_async", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue, ^{
        NSLog(@"1-----%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"2-----%@",[NSThread currentThread]);
    });
    
    dispatch_barrier_async(queue, ^{
        NSLog(@"barrier-----%@",[NSThread currentThread]);
    });
    /*
    dispatch_barrier_sync(queue, ^{
        NSLog(@"barrier-----%@",[NSThread currentThread]);
    });
     */
    
    dispatch_async(queue, ^{
        NSLog(@"3-----%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"4-----%@",[NSThread currentThread]);
    });
    
    NSLog(@"the end");
  • dispatch_group

隊列組:可以監(jiān)聽不同隊列中的多個任務(wù)執(zhí)行結(jié)束之后卑惜,進(jìn)行相應(yīng)的操作,以下兩種法驻售,效果是一樣的
  1. 隊列組用法示例露久,在指定任務(wù)1、2欺栗、3(無序)都執(zhí)行完成之后毫痕,執(zhí)行相應(yīng)的操作
    特點(diǎn):可以是監(jiān)聽多個隊列下的任務(wù)都執(zhí)行完畢
- (void)testDispatch_group {
    //創(chuàng)建隊列組
    dispatch_group_t group = dispatch_group_create();
    //創(chuàng)建并發(fā)隊列
    dispatch_queue_t firstQueue = dispatch_queue_create("firstQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t secondQueue = dispatch_queue_create("secondQueue", DISPATCH_QUEUE_CONCURRENT);

    //封裝任務(wù),添加到隊列并監(jiān)聽任務(wù)的執(zhí)行情況
    dispatch_group_async(group, firstQueue, ^{
        NSLog(@"1-----%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, firstQueue, ^{
        NSLog(@"2-----%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, secondQueue, ^{
        NSLog(@"3-----%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, secondQueue, ^{
        NSLog(@"4-----%@",[NSThread currentThread]);
    });
    
    dispatch_group_async_f(group, secondQueue, @"testText", functionWotk);
    
    /*
    攔截通知迟几,監(jiān)聽到所有所有任務(wù)執(zhí)行完畢消请,執(zhí)行相應(yīng)的操作
    下面的group指的是在哪個隊列組,而firstQueue指的是block任務(wù)在哪個對列中執(zhí)行
    dispatch_group_notify 內(nèi)部是異步執(zhí)行
     */
    dispatch_group_notify(group, firstQueue, ^{
        NSLog(@"the notify");
    });
    
    NSLog(@"the end");
}

void functionWotk (void * text) {
    NSLog(@"dispatch_group_async_f-----%@-----%@",[NSThread currentThread],text);
}
  1. 隊列組用法示例
- (void)testDispatch_groupEnterAndLeave {
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("testDispatch_groupEnterAndLeave", DISPATCH_QUEUE_CONCURRENT);
    
    /*
     在該方法后面的任務(wù)會被隊列組監(jiān)聽
     dispatch_group_enter與dispatch_group_leave成對使用类腮,對應(yīng)一進(jìn)一出
     */
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"1-----%@",[NSThread currentThread]);
        //監(jiān)聽到該任務(wù)執(zhí)行完畢
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"2-----%@",[NSThread currentThread]);
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"3-----%@",[NSThread currentThread]);
        dispatch_group_leave(group);
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"the notify");
    });
}
  • dispatch_semaphore

根據(jù)信號量實現(xiàn)多線程同步機(jī)制臊泰,用來管理對資源的并發(fā)訪問

dispatch_semaphore 有以下三個函數(shù)
dispatch_semaphore_t dispatch_semaphore_create(1);// 創(chuàng)建信號量,參數(shù):信號量的初值蚜枢,如果不大于0則會返回NULL

long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);// 等待降低信號量缸逃,接收一個信號和時間值(多為DISPATCH_TIME_FOREVER);若信號的信號量為0厂抽,則會阻塞當(dāng)前線程需频,直到信號量大于0或者經(jīng)過輸入的時間值;若信號量大于0筷凤,則會使信號量減1并返回昭殉,程序繼續(xù)住下執(zhí)行

long dispatch_semaphore_signal(dispatch_semaphore_t dsema);// 提高信號量, 使信號量加1并返回

下面提供的是一個出售火車票的場景用例

/**
 * 線程安全:使用 semaphore 加鎖
 * 初始化火車票數(shù)量、賣票窗口(線程安全)饲化、并開始賣票
 */
- (void)testTicketSale {
    NSLog(@"semaphore---begin");
    
    __block NSInteger ticketSurplusCount = 50;
    dispatch_semaphore_t semaphoreLock = dispatch_semaphore_create(1);

    // queue1 代表火車票售賣窗口1
    dispatch_queue_t queue1 = dispatch_queue_create("net.bujige.testQueue1", DISPATCH_QUEUE_SERIAL);
    // queue2 代表火車票售賣窗2
    dispatch_queue_t queue2 = dispatch_queue_create("net.bujige.testQueue2", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(queue1, ^{
        while (1) {
            dispatch_semaphore_wait(semaphoreLock, DISPATCH_TIME_FOREVER);// 相當(dāng)于加鎖
            
            if (ticketSurplusCount > 0) {//如果還有票莽鸭,繼續(xù)售賣
                ticketSurplusCount--;
                NSLog(@"%@", [NSString stringWithFormat:@"剩余票數(shù):%ld 窗口:queue1",ticketSurplusCount]);
                [NSThread sleepForTimeInterval:0.2];
                dispatch_semaphore_signal(semaphoreLock);// 相當(dāng)于解鎖
            } else { //如果已賣完,關(guān)閉售票窗口
                NSLog(@"所有火車票均已售完");
                dispatch_semaphore_signal(semaphoreLock);// 相當(dāng)于解鎖
                break;
            }
        }
    });
    
    dispatch_async(queue2, ^{
        while (1) {
            dispatch_semaphore_wait(semaphoreLock, DISPATCH_TIME_FOREVER);// 相當(dāng)于加鎖
            
            if (ticketSurplusCount > 0) {//如果還有票吃靠,繼續(xù)售賣
                ticketSurplusCount--;
                NSLog(@"%@", [NSString stringWithFormat:@"剩余票數(shù):%ld 窗口:queue2",ticketSurplusCount]);
                [NSThread sleepForTimeInterval:0.2];
                dispatch_semaphore_signal(semaphoreLock);// 相當(dāng)于解鎖
            } else { //如果已賣完硫眨,關(guān)閉售票窗口
                NSLog(@"所有火車票均已售完");
                dispatch_semaphore_signal(semaphoreLock);// 相當(dāng)于解鎖
                break;
            }
        }
    });
    //當(dāng)線程1執(zhí)行到dispatch_semaphore_wait這一行時,semaphore的信號量為1巢块,所以使信號量-1變?yōu)?礁阁,并且線程1繼續(xù)往下執(zhí)行;如果當(dāng)在線程1售票操作還沒執(zhí)行完的時候族奢,又有線程2來訪問姥闭,執(zhí)行dispatch_semaphore_wait時由于此時信號量為0,且時間為DISPATCH_TIME_FOREVER,所以會一直阻塞線程2(此時線程2處于等待狀態(tài))越走,直到線程1執(zhí)行完售票操作并且執(zhí)行完dispatch_semaphore_signal使信號量為1后棚品,線程2才能解除阻塞繼續(xù)住下執(zhí)行。以上可以保證同時只有一個線程執(zhí)行售票操作這部分block中的代碼
}

如果有地方理解錯誤廊敌,歡迎各位大佬指正铜跑,十分感謝!

推薦幾篇本文參考的博文

iOS超級超級詳細(xì)介紹GCD:對GCD的用法原理講的通俗骡澈,容易理解
iOS多線程:『GCD』詳盡總結(jié):十分詳盡
iOS多線程之GCD:對GCD API的標(biāo)注很全面

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末锅纺,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子肋殴,更是在濱河造成了極大的恐慌囤锉,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件护锤,死亡現(xiàn)場離奇詭異官地,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)烙懦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門驱入,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人修陡,你說我怎么就攤上這事】肾” “怎么了魄鸦?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長癣朗。 經(jīng)常有香客問我拾因,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任绢记,我火速辦了婚禮扁达,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蠢熄。我一直安慰自己跪解,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布签孔。 她就那樣靜靜地躺著叉讥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪饥追。 梳的紋絲不亂的頭發(fā)上图仓,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天,我揣著相機(jī)與錄音但绕,去河邊找鬼救崔。 笑死,一個胖子當(dāng)著我的面吹牛捏顺,可吹牛的內(nèi)容都是我干的六孵。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼草丧,長吁一口氣:“原來是場噩夢啊……” “哼狸臣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起昌执,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤烛亦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后懂拾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體煤禽,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年岖赋,在試婚紗的時候發(fā)現(xiàn)自己被綠了檬果。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡唐断,死狀恐怖选脊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情脸甘,我是刑警寧澤恳啥,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站丹诀,受9級特大地震影響钝的,放射性物質(zhì)發(fā)生泄漏翁垂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一硝桩、第九天 我趴在偏房一處隱蔽的房頂上張望沿猜。 院中可真熱鬧,春花似錦碗脊、人聲如沸啼肩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽疟游。三九已至,卻和暖如春痕支,著一層夾襖步出監(jiān)牢的瞬間颁虐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工卧须, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留另绩,地道東北人。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓花嘶,卻偏偏與公主長得像笋籽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子椭员,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355

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

  • 本文首發(fā)于我的個人博客:「程序員充電站」[https://itcharge.cn]文章鏈接:「傳送門」[https...
    ITCharge閱讀 347,945評論 308 1,926
  • 文用來介紹 iOS 多線程中 GCD 的相關(guān)知識以及使用方法车海。通過本文,您將了解到: 1. GCD 簡介 2. G...
    曉_我想去環(huán)游世界閱讀 1,146評論 2 8
  • 本文用來介紹 iOS 多線程中 GCD 的相關(guān)知識以及使用方法隘击。這大概是史上最詳細(xì)侍芝、清晰的關(guān)于 GCD 的詳細(xì)講...
    花花世界的孤獨(dú)行者閱讀 500評論 0 1
  • 728 羊湖水悠藍(lán), 立于四仞山埋同。 藏獒極溫順州叠, 花妍入心閑。 品味藏餐菜凶赁, 轉(zhuǎn)經(jīng)昭寺間咧栗。 編成十藏辮, 購串八廓...
    飛雪姐姐閱讀 186評論 0 0
  • 本月?lián)炝?個會員虱肄,下月計劃正式啟動致板,再此之前需要能夠完整的學(xué)習(xí)完張超毅的平凡企業(yè)家,真正的放空自己咏窿,學(xué)習(xí)進(jìn)去斟或,發(fā)現(xiàn)...
    余言_90a1閱讀 249評論 0 0