信號量的作用是用來控制資源/任務(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ù)隊列。