怎么讓線程同步

1、Dispatch Group

需要在大量任務(wù)都執(zhí)行完成后,執(zhí)行其他任務(wù),可以用 Dispatch Group

// 可以理解為一個(gè)任務(wù)組,組內(nèi)的任務(wù)完成后就會(huì)調(diào)用dispatch_group_notify
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

dispatch_group_async(group, queue, ^{
    for (int i = 0; i < 1000; i++) {
    if (i == 999) {
        NSLog(@"11111111");
    }
}

});

dispatch_group_async(group, queue, ^{
    NSLog(@"22222222");
});

dispatch_group_async(group, queue, ^{
    NSLog(@"33333333");
});

dispatch_group_notify(group, queue, ^{
    NSLog(@"done");
});

對于網(wǎng)絡(luò)請求這種異步任務(wù),還需要使用 dispatch_group_enter和dispatch_group_leave,來手動(dòng)處理下,先上代碼

dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

dispatch_group_enter(group);
dispatch_async(queue, ^{
    NSLog(@"任務(wù)1開始");
    sleep(2);
    NSLog(@"任務(wù)1結(jié)束");
    dispatch_group_leave(group);
});

dispatch_group_enter(group);
dispatch_async(queue, ^{
    NSLog(@"任務(wù)2開始");
    sleep(1);
    NSLog(@"任務(wù)2結(jié)束");
    dispatch_group_leave(group);
});

dispatch_group_notify(group, queue, ^{
    NSLog(@"完成了");
});

輸出為

17:31:39.314251+0800 testP[29849:2247791] 任務(wù)2開始
17:31:39.314251+0800 testP[29849:2247785] 任務(wù)1開始
17:31:40.317949+0800 testP[29849:2247791] 任務(wù)2結(jié)束
17:31:41.318231+0800 testP[29849:2247785] 任務(wù)1結(jié)束
17:31:41.318588+0800 testP[29849:2247785] 完成了

可以看到任務(wù)1和任務(wù)2同時(shí)執(zhí)行,因?yàn)槿蝿?wù)1耗時(shí)2秒,所以在任務(wù)2后1秒完成,然后發(fā)出通知,

dispatch_group_enter和dispatch_group_leave總是成對出現(xiàn),不然可能導(dǎo)致group沒有被釋放,從而沒有notify;或者group提前釋放,導(dǎo)致EXC_BAD_INSTRUCTION,group提前釋放

dispatch_group_enter和dispatch_group_leave可以理解為給group添加手動(dòng)計(jì)數(shù),dispatch_group_enter會(huì)給group加1,dispatch_group_leave就是減一,group初始計(jì)數(shù)為0。

當(dāng)group初始計(jì)數(shù)為0時(shí),就會(huì)執(zhí)行notify通知,比如如下代碼

dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

dispatch_group_notify(group, queue, ^{
    NSLog(@"完成了");
});

dispatch_group_enter(group);
dispatch_async(queue, ^{
    NSLog(@"任務(wù)1開始");
    sleep(2);
    NSLog(@"任務(wù)1結(jié)束");
    dispatch_group_leave(group);
});

dispatch_group_enter(group);
dispatch_async(queue, ^{
    NSLog(@"任務(wù)2開始");
    sleep(1);
    NSLog(@"任務(wù)2結(jié)束");
    dispatch_group_leave(group);
});


輸出為

17:45:46.296758+0800 testP[30209:2259157] 任務(wù)2開始
17:45:46.296758+0800 testP[30209:2259158] 任務(wù)1開始
17:45:46.296766+0800 testP[30209:2259150] 完成了
17:45:47.301499+0800 testP[30209:2259157] 任務(wù)2結(jié)束
17:45:48.299812+0800 testP[30209:2259158] 任務(wù)1結(jié)束

將dispatch_group_notify移到最前,就不會(huì)在group完成后得到notify,而是提前執(zhí)行了

2、dispatch_barrier_sync 和 dispatch_barrier_async

20150726170216381.png

dispatch_async(queue, ^{
    NSLog(@"1");
});

dispatch_async(queue, ^{
    NSLog(@"2");
});
dispatch_async(queue, ^{
    NSLog(@"3");
});


// dispatch_barrier_sync 這個(gè)和  dispatch_async與dispatch_sync之間的區(qū)別類似
dispatch_barrier_async(queue, ^{
    NSLog(@"000000");
});

dispatch_async(queue, ^{
    NSLog(@"4");
});

dispatch_async(queue, ^{
    NSLog(@"5");
});
dispatch_async(queue, ^{
    NSLog(@"6");
});

3、dispatch_semaphore

1、dispatch_semaphore_create 創(chuàng)建一個(gè)semaphore  就是創(chuàng)建一個(gè)全局的變量,小于0時(shí)會(huì)阻塞當(dāng)前線程
2、dispatch_semaphore_signal 發(fā)送一個(gè)信號(hào)       給信號(hào)量加1
3、dispatch_semaphore_wait 等待信號(hào)   給信號(hào)量減1

這個(gè)東西本質(zhì)是就是立flag,讓flag小于0,線程就阻塞了,只有讓flag大于0,才能繼續(xù)

網(wǎng)上的說明例子

// 創(chuàng)建隊(duì)列組
dispatch_group_t group = dispatch_group_create();
// 創(chuàng)建信號(hào)量,并且設(shè)置值為10
dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < 100; i++){
/*
 *  由于是異步執(zhí)行的,所以每次循環(huán)Block里面的dispatch_semaphore_signal根本還沒有執(zhí)行就會(huì)執(zhí)行dispatch_semaphore_wait,
 *  從而semaphore-1.當(dāng)循環(huán)10此后,semaphore等于0,則會(huì)阻塞線程,直到執(zhí)行了Block的dispatch_semaphore_signal 才會(huì)繼續(xù)執(zhí)行
 */

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    dispatch_group_async(group, queue, ^{
        NSLog(@"%i",i);
        sleep(2);
        // 每次發(fā)送信號(hào)則semaphore會(huì)+1,
        dispatch_semaphore_signal(semaphore);
    });
}

應(yīng)用1 網(wǎng)絡(luò)請求

_block BOOL isok = NO;

dispatch_semaphore_t sema = dispatch_semaphore_create(0);
Engine *engine = [[Engine alloc] init];
[engine queryCompletion:^(BOOL isOpen) {
    isok = isOpen;
    dispatch_semaphore_signal(sema);
} onError:^(int errorCode, NSString *errorMessage) {
    isok = NO;
    dispatch_semaphore_signal(sema);
}];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
// todo what you want to do after net callback

應(yīng)用2 獲取權(quán)限

//創(chuàng)建通訊簿的引用
addBook=ABAddressBookCreateWithOptions(NULL, NULL);
//創(chuàng)建一個(gè)出事信號(hào)量為0的信號(hào)
dispatch_semaphore_t sema=dispatch_semaphore_create(0);
//申請?jiān)L問權(quán)限
ABAddressBookRequestAccessWithCompletion(addBook, ^(bool greanted, CFErrorRef error)
{
    //greanted為YES是表示用戶允許,否則為不允許
    if (!greanted) {
        tip=1;
    }
    //發(fā)送一次信號(hào)
    dispatch_semaphore_signal(sema);

});
//等待信號(hào)觸發(fā)
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

4、其他各種鎖

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 背景 擔(dān)心了兩周的我終于輪到去醫(yī)院做胃鏡檢查了!去的時(shí)候我都想好了最壞的可能(胃癌),之前在網(wǎng)上查的癥狀都很相似。...
    Dely閱讀 9,393評論 21 42
  • 本文首發(fā)于我的個(gè)人博客:「程序員充電站」[https://itcharge.cn]文章鏈接:「傳送門」[https...
    ITCharge閱讀 350,641評論 308 1,927
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 30,224評論 8 265
  • 特別喜歡 冬天的夜晚 穿著厚厚的大衣 一個(gè)人走在大街上 聽著音樂、吃著糖葫蘆、漫步而行 雖然身體都要凍僵了 但心卻...
    生活_0000閱讀 148評論 0 1
  • #每日500字#Day 4# 最近撿起了許久不練的字帖,細(xì)細(xì)描摹,總會(huì)感慨一個(gè)人的字怎么可以如此舒暢有力。即使一絲...
    白米飯兒閱讀 798評論 0 0

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