iOS 趣談信號量dispatch_semaphore_t

信號量的作用是用來控制資源/任務(wù)的并發(fā)量。這個怎么理解呢?

舉個栗子:

體育課期中考試需要考核同一年級某個班的同學(xué)的體能是否達(dá)標(biāo),學(xué)校決定采用跑步并計算所用平均時間的方式,為了增加趣味及加強同學(xué)之間的凝聚力,體育老師們一致決定采用接力跑的方式,每個班級有3個接力棒,繞著足球場跑完一圈才可以交接棒,直到所有同學(xué)跑完為止。

那么我們可以想象一下是這樣的一個場景:某班有47位同學(xué),一開始因為只有三個接力棒,所以只能有三個同學(xué)站在起跑線,等發(fā)號槍響,三個同學(xué)就開始起跑,這里面有同學(xué)反應(yīng)快會起跑得好一些,有同學(xué)經(jīng)常鍛煉可能會更快跑完一圈然后交棒,也就是過程的多樣性問題,也比較貼合我們的編程的場景。

但是,在接力棒回來之前,剩下的44位同學(xué)只能在起跑點原地等待,直到正在進(jìn)行跑步的同學(xué)回來并交接下一位同學(xué)才能起跑,按照這樣的規(guī)則直到47位同學(xué)跑完即考核結(jié)束。

后話:計算47位同學(xué)跑一圈所用的平均時間即為某班的體能考核結(jié)果并全年級排名!

先看api:

dispatch_semaphore_create(long value)                                                                              --- ①
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout)      --- ②
dispatch_semaphore_signal(dispatch_semaphore_t dsema)                                             --- ③

這里對上面的api以及結(jié)合之前的栗子做一個說明:

所傳參數(shù) value 理解為一個班級的一次考試有多少個接力棒,也可以理解為我們編程時能夠分配的資源的數(shù)量

所傳參數(shù)dsema 也就是上面創(chuàng)建的信號量,timeout 理解為等待前面運行的任務(wù)執(zhí)行多長時間為止,上面跑步的例子是,現(xiàn)實場景是要一直等前面的同學(xué)回來才能繼續(xù)跑,而不是比如等10s沒有同學(xué)回來就可以繼續(xù)跑,沒有交接棒我們是不能跑的,那么我們這里的取值應(yīng)該是:DISPATCH_TIME_FOREVER,現(xiàn)實意義就是拿走一根接力棒,能夠繼續(xù)拿接力棒跑的名額少掉一個,當(dāng)沒有交接棒是空閑時所有同學(xué)都要等待前面至少一位同學(xué)跑完。

所傳參數(shù)dsema同理 也就是上面創(chuàng)建的信號量,這里的意義就是跑完一位同學(xué),釋放出一個接力棒,其他同學(xué)就有了接力棒可以拿著接力棒繼續(xù)跑。

需要注意的是:信號總數(shù)是應(yīng)該先減后加的,也就是先dispatch_semaphore_wait,后dispatch_semaphore_signal

demo:

dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    for (int i = 1; i <= 47; i++)
    {
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"學(xué)號為%d的同學(xué)開始跑",i);
        dispatch_async(queue, ^{
            int time = arc4random() % 5;
            sleep(time);
            NSLog(@"學(xué)號為%d同學(xué)跑完,用時:%d秒",i ,time);
            dispatch_semaphore_signal(semaphore);
        });
    }

留意一下控制臺里面輸出的內(nèi)容可以發(fā)現(xiàn):同一時刻最多有三位同學(xué)在跑步,也就是有三個任務(wù)在執(zhí)行,跑完一位同學(xué)才能有另一位同學(xué)繼續(xù)跑,直到47位同學(xué)都跑完位置。

output:

20xx-xx-xx 17:09:50.727 CZB[74203:9934779] 學(xué)號為1的同學(xué)開始跑
20xx-xx-xx 17:09:50.727 CZB[74203:9934779] 學(xué)號為2的同學(xué)開始跑
20xx-xx-xx 17:09:50.727 CZB[74203:9934779] 學(xué)號為3的同學(xué)開始跑
20xx-xx-xx 17:09:51.731 CZB[74203:9934870] 學(xué)號為3同學(xué)跑完,用時:1秒
20xx-xx-xx 17:09:51.732 CZB[74203:9934779] 學(xué)號為4的同學(xué)開始跑
20xx-xx-xx 17:09:53.731 CZB[74203:9934869] 學(xué)號為2同學(xué)跑完,用時:3秒
20xx-xx-xx 17:09:53.731 CZB[74203:9934779] 學(xué)號為5的同學(xué)開始跑
20xx-xx-xx 17:09:53.734 CZB[74203:9934870] 學(xué)號為4同學(xué)跑完,用時:2秒
20xx-xx-xx 17:09:53.734 CZB[74203:9934779] 學(xué)號為6的同學(xué)開始跑
20xx-xx-xx 17:09:53.735 CZB[74203:9934870] 學(xué)號為6同學(xué)跑完,用時:0秒
20xx-xx-xx 17:09:53.735 CZB[74203:9934779] 學(xué)號為7的同學(xué)開始跑
20xx-xx-xx 17:09:54.731 CZB[74203:9934861] 學(xué)號為1同學(xué)跑完,用時:4秒
20xx-xx-xx 17:09:54.732 CZB[74203:9934779] 學(xué)號為8的同學(xué)開始跑
20xx-xx-xx 17:09:55.740 CZB[74203:9934870] 學(xué)號為7同學(xué)跑完,用時:2秒
20xx-xx-xx 17:09:55.740 CZB[74203:9934779] 學(xué)號為9的同學(xué)開始跑
20xx-xx-xx 17:09:57.736 CZB[74203:9934869] 學(xué)號為5同學(xué)跑完,用時:4秒
20xx-xx-xx 17:09:57.736 CZB[74203:9934779] 學(xué)號為10的同學(xué)開始跑
20xx-xx-xx 17:09:57.738 CZB[74203:9934861] 學(xué)號為8同學(xué)跑完,用時:3秒
20xx-xx-xx 17:09:57.739 CZB[74203:9934779] 學(xué)號為11的同學(xué)開始跑
20xx-xx-xx 17:09:57.739 CZB[74203:9934861] 學(xué)號為11同學(xué)跑完,用時:0秒
20xx-xx-xx 17:09:57.740 CZB[74203:9934779] 學(xué)號為12的同學(xué)開始跑
20xx-xx-xx 17:09:58.743 CZB[74203:9934861] 學(xué)號為12同學(xué)跑完,用時:1秒
20xx-xx-xx 17:09:58.743 CZB[74203:9934870] 學(xué)號為9同學(xué)跑完,用時:3秒
20xx-xx-xx 17:09:58.743 CZB[74203:9934779] 學(xué)號為13的同學(xué)開始跑
20xx-xx-xx 17:09:58.744 CZB[74203:9934779] 學(xué)號為14的同學(xué)開始跑
20xx-xx-xx 17:09:58.744 CZB[74203:9934870] 學(xué)號為13同學(xué)跑完,用時:0秒
20xx-xx-xx 17:09:58.744 CZB[74203:9934779] 學(xué)號為15的同學(xué)開始跑
20xx-xx-xx 17:10:00.748 CZB[74203:9934870] 學(xué)號為15同學(xué)跑完,用時:2秒
20xx-xx-xx 17:10:00.749 CZB[74203:9934779] 學(xué)號為16的同學(xué)開始跑
20xx-xx-xx 17:10:01.741 CZB[74203:9934869] 學(xué)號為10同學(xué)跑完,用時:4秒
20xx-xx-xx 17:10:01.742 CZB[74203:9934779] 學(xué)號為17的同學(xué)開始跑
20xx-xx-xx 17:10:01.747 CZB[74203:9934861] 學(xué)號為14同學(xué)跑完,用時:3秒
20xx-xx-xx 17:10:01.748 CZB[74203:9934779] 學(xué)號為18的同學(xué)開始跑
20xx-xx-xx 17:10:01.748 CZB[74203:9934861] 學(xué)號為18同學(xué)跑完,用時:0秒
20xx-xx-xx 17:10:01.748 CZB[74203:9934779] 學(xué)號為19的同學(xué)開始跑
20xx-xx-xx 17:10:04.743 CZB[74203:9934869] 學(xué)號為17同學(xué)跑完,用時:3秒
20xx-xx-xx 17:10:04.743 CZB[74203:9934779] 學(xué)號為20的同學(xué)開始跑
20xx-xx-xx 17:10:04.753 CZB[74203:9934870] 學(xué)號為16同學(xué)跑完,用時:4秒
20xx-xx-xx 17:10:04.754 CZB[74203:9934779] 學(xué)號為21的同學(xué)開始跑
20xx-xx-xx 17:10:05.752 CZB[74203:9934861] 學(xué)號為19同學(xué)跑完,用時:4秒
20xx-xx-xx 17:10:05.752 CZB[74203:9934779] 學(xué)號為22的同學(xué)開始跑
20xx-xx-xx 17:10:07.744 CZB[74203:9934869] 學(xué)號為20同學(xué)跑完,用時:3秒
20xx-xx-xx 17:10:07.744 CZB[74203:9934779] 學(xué)號為23的同學(xué)開始跑
20xx-xx-xx 17:10:07.755 CZB[74203:9934861] 學(xué)號為22同學(xué)跑完,用時:2秒
20xx-xx-xx 17:10:07.755 CZB[74203:9934870] 學(xué)號為21同學(xué)跑完,用時:3秒
20xx-xx-xx 17:10:07.756 CZB[74203:9934779] 學(xué)號為24的同學(xué)開始跑
20xx-xx-xx 17:10:07.756 CZB[74203:9934779] 學(xué)號為25的同學(xué)開始跑
20xx-xx-xx 17:10:09.756 CZB[74203:9934861] 學(xué)號為25同學(xué)跑完,用時:2秒
20xx-xx-xx 17:10:09.757 CZB[74203:9934779] 學(xué)號為26的同學(xué)開始跑
20xx-xx-xx 17:10:09.757 CZB[74203:9934861] 學(xué)號為26同學(xué)跑完,用時:0秒
20xx-xx-xx 17:10:09.757 CZB[74203:9934779] 學(xué)號為27的同學(xué)開始跑
20xx-xx-xx 17:10:09.758 CZB[74203:9934861] 學(xué)號為27同學(xué)跑完,用時:0秒
20xx-xx-xx 17:10:09.758 CZB[74203:9934779] 學(xué)號為28的同學(xué)開始跑
20xx-xx-xx 17:10:10.748 CZB[74203:9934869] 學(xué)號為23同學(xué)跑完,用時:3秒
20xx-xx-xx 17:10:10.748 CZB[74203:9934779] 學(xué)號為29的同學(xué)開始跑
20xx-xx-xx 17:10:11.751 CZB[74203:9934869] 學(xué)號為29同學(xué)跑完,用時:1秒
20xx-xx-xx 17:10:11.751 CZB[74203:9934779] 學(xué)號為30的同學(xué)開始跑
20xx-xx-xx 17:10:11.752 CZB[74203:9934869] 學(xué)號為30同學(xué)跑完,用時:0秒
20xx-xx-xx 17:10:11.752 CZB[74203:9934779] 學(xué)號為31的同學(xué)開始跑
20xx-xx-xx 17:10:11.761 CZB[74203:9934870] 學(xué)號為24同學(xué)跑完,用時:4秒
20xx-xx-xx 17:10:11.761 CZB[74203:9934779] 學(xué)號為32的同學(xué)開始跑
20xx-xx-xx 17:10:12.761 CZB[74203:9934861] 學(xué)號為28同學(xué)跑完,用時:3秒
20xx-xx-xx 17:10:12.761 CZB[74203:9934779] 學(xué)號為33的同學(xué)開始跑
20xx-xx-xx 17:10:12.764 CZB[74203:9934870] 學(xué)號為32同學(xué)跑完,用時:1秒
20xx-xx-xx 17:10:12.764 CZB[74203:9934779] 學(xué)號為34的同學(xué)開始跑
20xx-xx-xx 17:10:12.765 CZB[74203:9934870] 學(xué)號為34同學(xué)跑完,用時:0秒
20xx-xx-xx 17:10:12.765 CZB[74203:9934779] 學(xué)號為35的同學(xué)開始跑
20xx-xx-xx 17:10:15.755 CZB[74203:9934869] 學(xué)號為31同學(xué)跑完,用時:4秒
20xx-xx-xx 17:10:15.755 CZB[74203:9934779] 學(xué)號為36的同學(xué)開始跑
20xx-xx-xx 17:10:15.755 CZB[74203:9934869] 學(xué)號為36同學(xué)跑完,用時:0秒
20xx-xx-xx 17:10:15.756 CZB[74203:9934779] 學(xué)號為37的同學(xué)開始跑
20xx-xx-xx 17:10:15.766 CZB[74203:9934870] 學(xué)號為35同學(xué)跑完,用時:3秒
20xx-xx-xx 17:10:15.767 CZB[74203:9934779] 學(xué)號為38的同學(xué)開始跑
20xx-xx-xx 17:10:16.765 CZB[74203:9934861] 學(xué)號為33同學(xué)跑完,用時:4秒
20xx-xx-xx 17:10:16.765 CZB[74203:9934779] 學(xué)號為39的同學(xué)開始跑
20xx-xx-xx 17:10:17.760 CZB[74203:9934869] 學(xué)號為37同學(xué)跑完,用時:2秒
20xx-xx-xx 17:10:17.760 CZB[74203:9934779] 學(xué)號為40的同學(xué)開始跑
20xx-xx-xx 17:10:17.760 CZB[74203:9934869] 學(xué)號為40同學(xué)跑完,用時:0秒
20xx-xx-xx 17:10:17.761 CZB[74203:9934779] 學(xué)號為41的同學(xué)開始跑
20xx-xx-xx 17:10:17.767 CZB[74203:9934861] 學(xué)號為39同學(xué)跑完,用時:1秒
20xx-xx-xx 17:10:17.768 CZB[74203:9934779] 學(xué)號為42的同學(xué)開始跑
20xx-xx-xx 17:10:17.768 CZB[74203:9934861] 學(xué)號為42同學(xué)跑完,用時:0秒
20xx-xx-xx 17:10:17.768 CZB[74203:9934779] 學(xué)號為43的同學(xué)開始跑
20xx-xx-xx 17:10:18.774 CZB[74203:9934861] 學(xué)號為43同學(xué)跑完,用時:1秒
20xx-xx-xx 17:10:18.775 CZB[74203:9934779] 學(xué)號為44的同學(xué)開始跑
20xx-xx-xx 17:10:19.772 CZB[74203:9934870] 學(xué)號為38同學(xué)跑完,用時:4秒
20xx-xx-xx 17:10:19.772 CZB[74203:9934779] 學(xué)號為45的同學(xué)開始跑
20xx-xx-xx 17:10:19.772 CZB[74203:9934870] 學(xué)號為45同學(xué)跑完,用時:0秒
20xx-xx-xx 17:10:19.773 CZB[74203:9934779] 學(xué)號為46的同學(xué)開始跑
20xx-xx-xx 17:10:21.764 CZB[74203:9934869] 學(xué)號為41同學(xué)跑完,用時:4秒
20xx-xx-xx 17:10:21.764 CZB[74203:9934779] 學(xué)號為47的同學(xué)開始跑
20xx-xx-xx 17:10:22.773 CZB[74203:9934870] 學(xué)號為46同學(xué)跑完,用時:3秒
20xx-xx-xx 17:10:22.779 CZB[74203:9934861] 學(xué)號為44同學(xué)跑完,用時:4秒
20xx-xx-xx 17:10:23.769 CZB[74203:9934869] 學(xué)號為47同學(xué)跑完,用時:2秒

還有一個情況,如果想要提前結(jié)束考核,也就是結(jié)束任務(wù)那怎么辦,我們回過頭來再看一下dispatch_semaphore_create(long value)dispatch_semaphore_wait () 。每執(zhí)行一次dispatch_semaphore_wait () 對應(yīng)的信號總量的值: value值就會減一,當(dāng)信用總量的值小于0時,將會結(jié)束所有的任務(wù)。

我們改一下代碼:

dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    for (int i = 1; i <= 47; i++)
    {
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        
        if (i == 7) {
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        }
        
        NSLog(@"學(xué)號為%d的同學(xué)開始跑",i);
        
        dispatch_async(queue, ^{
            int time = arc4random() % 5;
            sleep(time);
            NSLog(@"學(xué)號為%d同學(xué)跑完,用時:%d秒",i ,time);
            dispatch_semaphore_signal(semaphore);
        });
    }

當(dāng) i == 7時,我們調(diào)用 dispatch_semaphore_wait () 4次,每調(diào)用一次信號量減1,由于我們總共只有3個信號量,所以會導(dǎo)致任務(wù)執(zhí)行結(jié)束。

控制臺輸出結(jié)果是:

2017-10-31 17:38:01.228 CZB[74583:10003955] 學(xué)號為1的同學(xué)開始跑
2017-10-31 17:38:01.228 CZB[74583:10003955] 學(xué)號為2的同學(xué)開始跑
2017-10-31 17:38:01.228 CZB[74583:10003955] 學(xué)號為3的同學(xué)開始跑
2017-10-31 17:38:02.228 CZB[74583:10004053] 學(xué)號為1同學(xué)跑完,用時:1秒
2017-10-31 17:38:02.229 CZB[74583:10003955] 學(xué)號為4的同學(xué)開始跑
2017-10-31 17:38:02.230 CZB[74583:10004053] 學(xué)號為4同學(xué)跑完,用時:0秒
2017-10-31 17:38:02.230 CZB[74583:10003955] 學(xué)號為5的同學(xué)開始跑
2017-10-31 17:38:03.231 CZB[74583:10004053] 學(xué)號為5同學(xué)跑完,用時:1秒
2017-10-31 17:38:03.231 CZB[74583:10004045] 學(xué)號為3同學(xué)跑完,用時:2秒
2017-10-31 17:38:03.232 CZB[74583:10003955] 學(xué)號為6的同學(xué)開始跑
2017-10-31 17:38:03.232 CZB[74583:10004045] 學(xué)號為6同學(xué)跑完,用時:0秒
2017-10-31 17:38:04.228 CZB[74583:10004052] 學(xué)號為2同學(xué)跑完,用時:3秒

因此,如果想要提前結(jié)束任務(wù)可以根據(jù)具體情況執(zhí)行 dispatch_semaphore_wait ()來中斷任務(wù)隊列。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • Managing Units of Work(管理工作單位) 調(diào)度塊允許您直接配置隊列中各個工作單元的屬性。它們還...
    edison0428閱讀 8,051評論 0 1
  • 理解這個概念之前,先拋出一個問題 問題描述: 假設(shè)現(xiàn)在系統(tǒng)有兩個空閑資源可以被利用,但同一時間卻有三個線程要進(jìn)行訪...
    Mr在水一方閱讀 341評論 0 1
  • 背景 擔(dān)心了兩周的我終于輪到去醫(yī)院做胃鏡檢查了!去的時候我都想好了最壞的可能(胃癌),之前在網(wǎng)上查的癥狀都很相似。...
    Dely閱讀 9,277評論 21 42
  • 我使用CocoaPods安裝。如果CocoaPods不會安裝自行查方法吧,東西比較多,本文不做贅述。 iOS安裝C...
    高談闊論閱讀 470評論 0 0
  • “等我股票回本了,就跟你離婚。” 她聽完心里暖暖的,她想,這大概是最海枯石爛的承諾。
    最愛水果君Lareina閱讀 126評論 0 0