一、定義
1、信號量:就是一種可用來控制訪問資源的數量的標識,設定了一個信號量,在線程訪問之前,加上信號量的處理,則可告知系統按照我們指定的信號量數量來執行多個線程。
其實,這有點類似鎖機制了,只不過信號量都是系統幫助我們處理了,我們只需要在執行線程之前,設定一個信號量值,并且在使用時,加上信號量處理方法就行了。2、簡單來講 信號量為0則阻塞線程,大于0則不會阻塞。則我們通過改變信號量的值,來控制是否阻塞線程,從而達到線程同步
-
3、信號量主要有3個函數,分別是:
//創建信號量,參數:信號量的初值,如果小于0則會返回NULL dispatch_semaphore_create(信號量值) //等待降低信號量 dispatch_semaphore_wait(信號量,等待時間) //提高信號量 dispatch_semaphore_signal(信號量)
-
4、關于信號量,一般可以用停車來比喻
停車場剩余4個車位,那么即使同時來了四輛車也能停的下。如果此時來了五輛車,那么就有一輛需要等待。信號量的值就相當于剩余車位的數目。
dispatch_semaphore_wait
函數就相當于來了一輛車,dispatch_semaphore_signal
就相當于走了一輛車。停車位的剩余數目在初始化的時候就已經指明了(dispatch_semaphore_create(long value)
),調用一次dispatch_semaphore_signal
,剩余的車位就增加一個;調用一次dispatch_semaphore_wait
剩余車位就減少一個;當剩余車位為0時,再來車(即調用dispatch_semaphore_wait
)就只能等待。有可能同時有幾輛車等待一個停車位。有些車主沒有耐心,給自己設定了一段等待時間,這段時間內等不到停車位就走了,如果等到了就開進去停車。而有些車主就像把車停在這,所以就一直等下去。
二、使用場景1
假設現在系統有兩個空閑資源可以被利用,但同一時間卻有三個線程要進行訪問,這種情況下,該如何處理呢?
//crate的value表示,最多幾個資源可訪問
dispatch_semaphore_t samphore = dispatch_semaphore_create(2);
dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//dispatch_queue_t quene = dispatch_queue_create("com.anji.jiajia", DISPATCH_QUEUE_CONCURRENT);
//任務1
dispatch_async(quene, ^{
dispatch_semaphore_wait(samphore, DISPATCH_TIME_FOREVER);
NSLog(@"run task 1");
sleep(1);
NSLog(@"completed task 1");
dispatch_semaphore_signal(samphore);
});
//任務2
dispatch_async(quene, ^{
dispatch_semaphore_wait(samphore, DISPATCH_TIME_FOREVER);
NSLog(@"run task 2");
sleep(1);
NSLog(@"completed task 2");
dispatch_semaphore_signal(samphore);
});
//任務3
dispatch_async(quene, ^{
dispatch_semaphore_wait(samphore, DISPATCH_TIME_FOREVER);
NSLog(@"run task 3");
sleep(1);
NSLog(@"completed task 3");
dispatch_semaphore_signal(samphore);
});
運行結果:
2017-12-20 13:35:34.308282+0800 OCDemo[61949:15613320] run task 1
2017-12-20 13:35:34.308291+0800 OCDemo[61949:15613317] run task 2
2017-12-20 13:35:35.310784+0800 OCDemo[61949:15613320] completed task 1
2017-12-20 13:35:35.310784+0800 OCDemo[61949:15613317] completed task 2
2017-12-20 13:35:35.311016+0800 OCDemo[61949:15613319] run task 3
2017-12-20 13:35:36.313924+0800 OCDemo[61949:15613319] completed task 3
三、使用場景2
我們要下載很多圖片,并發異步進行,每個下載都會開辟一個新線程,可是我們又擔心太多線程肯定cpu吃不消,那么我們這里也可以用信號量控制一下最大開辟線程數。
//crate的value表示,最多幾個資源可訪問
dispatch_semaphore_t samphore = dispatch_semaphore_create(5);
dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < 15; i++) {
dispatch_async(quene, ^{
dispatch_semaphore_wait(samphore, DISPATCH_TIME_FOREVER);
NSLog(@"run task %d", i);
[self downloadImge:^(BOOL isSuccess, NSString *errorMsg) {
NSLog(@"BLock completed %d", i);
dispatch_semaphore_signal(samphore);
}];
});
}
由于是異步執行的,所以每次循環Block就會執行dispatch_semaphore_wait
,從而semaphore-1
.當循環5次后semaphore==0
,則會阻塞線程,直到執行了Block的dispatch_semaphore_signal
才會繼續執行。
四、使用場景3
在開發中我們需要處理下載多張照片等待所有網絡回調完之后才執行后面的操作。或者等待多個網絡請求,所有請求成功后數據融合處理。
//crate的value表示,最多幾個資源可訪問
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < 5; i++) {
dispatch_group_async(group, quene, ^{
dispatch_semaphore_t samphore = dispatch_semaphore_create(0);
[self downloadImge:^(BOOL isSuccess, NSString *errorMsg) {
NSLog(@"task %d completed ", i);
dispatch_semaphore_signal(samphore);
}];
dispatch_semaphore_wait(samphore, DISPATCH_TIME_FOREVER);
});
}
dispatch_group_notify(group, quene, ^{
NSLog(@"All task completed ====");
});
運行結果:
2017-12-20 14:22:03.162137+0800 OCDemo[64177:15790354] task 0 completed
2017-12-20 14:22:03.162138+0800 OCDemo[64177:15790351] task 3 completed
2017-12-20 14:22:04.165827+0800 OCDemo[64177:15790352] task 2 completed
2017-12-20 14:22:05.167003+0800 OCDemo[64177:15790368] task 4 completed
2017-12-20 14:22:05.166964+0800 OCDemo[64177:15790353] task 1 completed
2017-12-20 14:22:05.167153+0800 OCDemo[64177:15790368] All task completed ====