信號量是一個整形值并且具有一個初始計數(shù)值,并且支持兩個操作:信號通知和等待。當(dāng)一個信號量被信號通知,其計數(shù)會被增加。當(dāng)一個線程在一個信號量上等待時,線程會被阻塞(如果有必要的話),直至計數(shù)器大于零,然后線程會減少這個計數(shù)。
在GCD中有三個函數(shù)是semaphore的操作,分別是:
dispatch_semaphore_create 創(chuàng)建一個semaphore
dispatch_semaphore_signal 發(fā)送一個信號
dispatch_semaphore_wait 等待信號
簡單的介紹一下這三個函數(shù),第一個函數(shù)有一個整形的參數(shù),我們可以理解為信號的總量,dispatch_semaphore_signal是發(fā)送一個信號,自然會讓信號總量加1,dispatch_semaphore_wait等待信號,當(dāng)信號總量少于0的時候就會一直等待,否則就可以正常的執(zhí)行,并讓信號總量-1,根據(jù)這樣的原理,我們便可以快速的創(chuàng)建一個并發(fā)控制來同步任務(wù)和有限資源訪問控制
__block int mainData = 0;
int data = 3;
__block dispatch_semaphore_t sem = dispatch_semaphore_create(0);
dispatch_queue_t queue = dispatch_queue_create("StudyBlocks", NULL);
dispatch_async(queue, ^(void) {
int sum = 0;
for(int i = 0; i < 5; i++)
{
sum += data;
NSLog(@" >> Sum: %d", sum);
}
dispatch_semaphore_signal(sem);
});
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
for(int j=0;j<5;j++)
{
mainData++;
NSLog(@">> Main Data: %d",mainData);
}
在GCD中有三個函數(shù)跟semaphore相關(guān),分別是:
1: public func dispatch_semaphore_create(value: Int) ->dispatch_semaphore_t!
該函數(shù)使用一個初始值創(chuàng)建一個dispatch_semaphore_t類型的信號量,注意:這里的傳入的參數(shù)value必須大于或等于0,否則dispatch_semaphore_create會返回NULL
2: public func dispatch_semaphore_wait(dsema: dispatch_semaphore_t,_ timeout:dispatch_time_t) ->Int
等待信號量,該函數(shù)會使傳入的信號量dsema的值減1
dsema: 信號量
timeout: dispatch_time_t類型。比較有用的兩個宏:DISPATCH_TIME_NOW(表示當(dāng)前)和DISPATCH_TIME_FOREVER (表示遙遠(yuǎn)的未來)。一般可以直接設(shè)置timeout為這兩個宏其中的一個,或者自己創(chuàng)建一個dispatch_time_t類型的變量。創(chuàng)建dispatch_time_t類型的變量有兩種方法,dispatch_time和dispatch_walltime。
利用創(chuàng)建dispatch_time創(chuàng)建dispatch_time_t類型變量的時候一般也會用到這兩個變量。dispatch_time的聲明如下:
public func dispatch_time(when: dispatch_time_t,_ delta:Int64) ->dispatch_time_t;
其參數(shù)when需傳入一個dispatch_time_t類型的變量,和一個delta值。表示when加delta(單位值是納秒)時間就是timeout的時間。
例如:dispatch_time_t t = dispatch_time(DISPATCH_TIME_NOW,1*NSEC_PER_SEC);
表示當(dāng)前時間向后延時一秒為timeout的時間,這里設(shè)置為1秒。
函數(shù)的作用:如果dsema信號量的值大于0,該函數(shù)所處線程就繼續(xù)執(zhí)行下面的語句,并且將信號量的值減1;
如果desema的值為0,那么這個函數(shù)就阻塞當(dāng)前線程等待timeout(注意timeout的類型為dispatch_time_t,需要傳入對應(yīng)的類型參數(shù)),如果等待的期間desema的值被dispatch_semaphore_signal函數(shù)加1了,且該函數(shù)(即dispatch_semaphore_wait)所處線程獲得了信號量,那么就繼續(xù)向下執(zhí)行并將信號量減1。
如果等待期間沒有獲取到信號量或者信號量的值一直為0,那么等到timeout時,其所處線程自動執(zhí)行其后語句。
3:public func dispatch_semaphore_signal(dsema: dispatch_semaphore_t) ->Int
發(fā)送一個信號,這個函數(shù)會使傳入的信號量dsema的值加1
當(dāng)返回值為0時表示當(dāng)前并沒有線程等待其處理的信號量,其處理的信號量的值加1即可。當(dāng)返回值不為0時,表示其當(dāng)前有(一個或多個)線程等待其處理的信號量,并且該函數(shù)喚醒了一個等待的線程(當(dāng)線程有優(yōu)先級時,喚醒優(yōu)先級最高的線程;否則隨機喚醒.
關(guān)于信號量,借用別人的一個例子:一般可以用停車來比喻。
停車場剩余4個車位,那么即使同時來了四輛車也能停的下。如果此時來了五輛車,那么就有一輛需要等待。信號量的值就相當(dāng)于剩余車位的數(shù)目,dispatch_semaphore_wait函數(shù)就相當(dāng)于來了一輛車,dispatch_semaphore_signal。就相當(dāng)于走了一輛車。停車位的剩余數(shù)目在初始化的時候就已經(jīng)指明了(dispatch_semaphore_create(value:Int))),調(diào)用一次dispatch_semaphore_signal,剩余的車位就增加一個;調(diào)用一次dispatch_semaphore_wait剩余車位就減少一個;當(dāng)剩余車位為0時,再來車(即調(diào)用dispatch_semaphore_wait)就只能等待。有可能同時有幾輛車等待一個停車位。有些車主。沒有耐心,給自己設(shè)定了一段等待時間,這段時間內(nèi)等不到停車位就走了,如果等到了就開進(jìn)去停車。而有些車主就像把車停在這,所以就一直等下去。