GCD - dispatch_semaphore(信號(hào)量)的理解及使用

簡(jiǎn)介

先來(lái)看看這幾個(gè)主要函數(shù):

/* 
功能:創(chuàng)建信號(hào)量
參數(shù):value:信號(hào)量的初值,如果小于0則會(huì)返回NULL
返回值:信號(hào)量或空(失?。?*/
dispatch_semaphore_t dispatch_semaphore_create(long value);

/*
功能:阻塞當(dāng)前線程等待降低信號(hào)量;
當(dāng)信號(hào)量>0時(shí),繼續(xù)往下執(zhí)行并讓信號(hào)量減1
當(dāng)信號(hào)量=0時(shí),那么會(huì)等待信號(hào)量為非零才會(huì)執(zhí)行下一步
或是時(shí)間結(jié)束,執(zhí)行下一步
參數(shù):dsema:信號(hào)量 timeout:限定時(shí)間
返回值:信號(hào)量強(qiáng)度
*/
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);


/* 
功能:執(zhí)行結(jié)束,不需要占用資源,提高信號(hào)量+1
參數(shù):dsema:信號(hào)量
返回值:信號(hào)量強(qiáng)度
*/
long dispatch_semaphore_signal(dispatch_semaphore_t dsema);

可以理解為馬路上的車道,
當(dāng)信號(hào)量為1的時(shí)候就是1個(gè)車道,
當(dāng)信號(hào)量為2的時(shí)候就是2個(gè)車道允許兩輛車同時(shí)通過(guò)(兩個(gè)線程同時(shí)執(zhí)行)

信號(hào)量為1的時(shí)候可以控制線程執(zhí)行順序

某種意義上和 NSOperationQueue比較相似
信號(hào)量就是maxConcurrentOperationCount

示例1: 信號(hào)量1時(shí),控制線程執(zhí)行順序

    //value 有幾個(gè)車道
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //任務(wù)1
    dispatch_async(quene, ^{
//        NSLog(@"車1 發(fā)動(dòng)");
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"車1 開(kāi)始通過(guò)");
        sleep(2);
        NSLog(@"車1 已通過(guò)");
        dispatch_semaphore_signal(semaphore);
    });
    //任務(wù)2
    dispatch_async(quene, ^{
//        NSLog(@"車2 發(fā)動(dòng)");
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"車2 開(kāi)始通過(guò)");
        sleep(3);
        NSLog(@"車2 已通過(guò)");
        dispatch_semaphore_signal(semaphore);
    });
    //任務(wù)3
    dispatch_async(quene, ^{
//        NSLog(@"車3 發(fā)動(dòng)");
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"車3 開(kāi)始通過(guò)");
        sleep(1);
        NSLog(@"車3 已通過(guò)");
        dispatch_semaphore_signal(semaphore);
    });

輸出結(jié)果

2018-01-03 12:01:17.239713+0800 GCD_Demo[1068:198835] 車1 開(kāi)始通過(guò)
2018-01-03 12:01:19.242800+0800 GCD_Demo[1068:198835] 車1 已通過(guò)
2018-01-03 12:01:19.243025+0800 GCD_Demo[1068:199498] 車2 開(kāi)始通過(guò)
2018-01-03 12:01:22.248172+0800 GCD_Demo[1068:199498] 車2 已通過(guò)
2018-01-03 12:01:22.248436+0800 GCD_Demo[1068:199521] 車3 開(kāi)始通過(guò)
2018-01-03 12:01:23.253654+0800 GCD_Demo[1068:199521] 車3 已通過(guò)

這個(gè)案例中有個(gè)問(wèn)題
這個(gè)案例的前提條件是dispatch_semaphore_wait能按照順序執(zhí)行,但是三個(gè)任務(wù)都處于不同的線程,不能完全保證按照順序執(zhí)行;
當(dāng)然在正常情況下是沒(méi)問(wèn)題的,但是如果在dispatch_semaphore_wait之前加入NSLog(NSLog不僅僅只是打印信息,還記錄到log中應(yīng)該屬于耗時(shí)操作)
在案例中就是 NSLog(@"車1 發(fā)動(dòng)"); 注釋的相關(guān)代碼,輸出結(jié)果很不穩(wěn)定

2018-01-03 13:39:07.971221+0800 GCD_Demo[1280:300474] 車1 發(fā)動(dòng)
2018-01-03 13:39:07.971221+0800 GCD_Demo[1280:301289] 車2 發(fā)動(dòng)
2018-01-03 13:39:07.971241+0800 GCD_Demo[1280:301301] 車3 發(fā)動(dòng)
2018-01-03 13:39:07.971365+0800 GCD_Demo[1280:301289] 車2 開(kāi)始通過(guò)
2018-01-03 13:39:10.973622+0800 GCD_Demo[1280:301289] 車2 已通過(guò)
2018-01-03 13:39:10.973885+0800 GCD_Demo[1280:300474] 車1 開(kāi)始通過(guò)
2018-01-03 13:39:12.979111+0800 GCD_Demo[1280:300474] 車1 已通過(guò)
2018-01-03 13:39:12.979332+0800 GCD_Demo[1280:301301] 車3 開(kāi)始通過(guò)
2018-01-03 13:39:13.980507+0800 GCD_Demo[1280:301301] 車3 已通過(guò)

使用注意點(diǎn)

使用過(guò)程中避免在dispatch_semaphore_wait之前加入代碼

示例2: 信號(hào)量為2的時(shí)候,資源池的運(yùn)用
//value 有幾個(gè)車道
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);
    dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //任務(wù)1
    dispatch_async(quene, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"車1 開(kāi)始通過(guò)");
        sleep(2);
        NSLog(@"車1 已通過(guò)");
        dispatch_semaphore_signal(semaphore);
    });
    //任務(wù)2
    dispatch_async(quene, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"車2 開(kāi)始通過(guò)");
        sleep(4);
        NSLog(@"車2 已通過(guò)");
        dispatch_semaphore_signal(semaphore);
    });
    //任務(wù)3
    dispatch_async(quene, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"車3 開(kāi)始通過(guò)");
        sleep(1);
        NSLog(@"車3 已通過(guò)");
        dispatch_semaphore_signal(semaphore);
    });

輸出結(jié)果

2018-01-03 13:56:23.688576+0800 GCD_Demo[1363:365452] 車1 開(kāi)始通過(guò)
2018-01-03 13:56:23.688576+0800 GCD_Demo[1363:365436] 車2 開(kāi)始通過(guò)
2018-01-03 13:56:25.691141+0800 GCD_Demo[1363:365452] 車1 已通過(guò)
2018-01-03 13:56:25.691367+0800 GCD_Demo[1363:365435] 車3 開(kāi)始通過(guò)
2018-01-03 13:56:26.696554+0800 GCD_Demo[1363:365435] 車3 已通過(guò)
2018-01-03 13:56:27.690969+0800 GCD_Demo[1363:365436] 車2 已通過(guò)

從輸出結(jié)果中的時(shí)間中看出,同時(shí)使用了兩個(gè)資源,總耗時(shí)4s與預(yù)期結(jié)果一直。

總結(jié): dispatch_semaphore 適合做多線程的資源池相關(guān)的功能,不太不適合做多線程同步相關(guān)的功能

最后編輯于
?著作權(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),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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