信號量是基于計數(shù)器的一種多線程同步機(jī)制不跟,用來管理對資源的并發(fā)訪問。
信號量內(nèi)部有一個可以原子遞增或遞減的值锻煌。如果一個動作嘗試減少信號量的值佩迟,使其小于0瞧毙,那么這個動作將會被阻塞驾锰,直到有其他調(diào)用者(在其他線程中)增加該信號量的值宵凌。
信號量就是一種可用來控制訪問資源的數(shù)量的標(biāo)識,設(shè)定了一個信號量裙椭,在線程訪問之前揩慕,加上信號量的處理藤肢,則可告知系統(tǒng)按照我們指定的信號量數(shù)量來執(zhí)行多個線程圆兵。
有點(diǎn)類似鎖機(jī)制跺讯,只不過信號量都是系統(tǒng)幫助我們處理,只需要在執(zhí)行線程之前殉农,設(shè)定一個信號量值,并且在使用時局荚,加上信號量處理方法就行了超凳。
簡單來講 信號量為0則阻塞線程,大于0則不會阻塞耀态。則我們通過改變信號量的值轮傍,來控制是否阻塞線程,從而達(dá)到線程同步首装。
dispatch_semaphore相關(guān)的3個函數(shù)
-
dispatch_semaphore_create
創(chuàng)建一個Semaphore并初始化信號的總量
/*!
* @function dispatch_semaphore_create
* @abstract 創(chuàng)建一個新的信號量
* @param value 信號量的初始值创夜,傳入小于0的數(shù)返回NULL
*/
dispatch_semaphore_t
dispatch_semaphore_create(long value);
-
dispatch_semaphore_wait
可以使總信號量減1,當(dāng)信號總量為0時就會一直等待(阻塞所在線程)仙逻,否則就可以正常執(zhí)行驰吓。
/*!
* @function dispatch_semaphore_wait
*
* @abstract 等待信號量
* Wait (decrement) for a semaphore.
* @param dsema 創(chuàng)建好的信號量
* @param timeout 信號等待時間,一般使用DISPATCH_TIME_FOREVER系奉,在得到signal之前一直等待
*/
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
-
dispatch_semaphore_signal
發(fā)送一個信號檬贰,讓信號總量加1
/*!
* @function dispatch_semaphore_signal
*
* @abstract 提高信號量, 使信號量加1并返回
* @param dsema 已創(chuàng)建好的信號
*/
dispatch_semaphore_signal(dispatch_semaphore_t dsema);
dispatch_semaphore主要應(yīng)用于兩個方面
-
線程同步
直接上代碼
- (void)semaphoreTest {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block long j = 0;
dispatch_async(queue, ^{
for (NSInteger i = 0; i < 1000; i ++) {
j ++;
}
dispatch_semaphore_signal(semaphore);
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"%ld",j);
}
//運(yùn)行結(jié)果:2018-05-23 17:56:48.064 MultiThreadingDemo[2955:535470] 1000
代碼說明:block塊異步執(zhí)行添加到了全局并發(fā)隊列里缺亮,所以程序在主線程會跳過block塊(同時開辟子線程異步執(zhí)行block塊)翁涤,執(zhí)行塊外的代碼dispatch_semaphore_wait,因為semaphore信號量為0萌踱,且時間為DISPATCH_TIME_FOREVER葵礼,所以會阻塞當(dāng)前線程(主線程),進(jìn)而只執(zhí)行子線程的block塊并鸵,直到執(zhí)行塊內(nèi)部的dispatch_semaphore_signal使得信號量+1鸳粉。正在被阻塞的線程(主線程)會恢復(fù)繼續(xù)執(zhí)行。這樣保證了線程之間的同步能真。
-
為線程加鎖赁严,限制并發(fā)線程數(shù)量
使用dispatch_semaphore_create(0);
保證在同一時間只有一個線程訪問扰柠,實(shí)現(xiàn)加鎖功能。關(guān)于限制線程數(shù)量疼约,我們用一個停車場的demo看一下:
//停車場demo
- (void)parkingAreaADemo {
//假設(shè)目前有3個停車位
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//有10輛車過來打算停車
for (NSInteger i = 1; i <= 10; i ++) {
dispatch_async(queue, ^{
NSInteger carId = i;
if (carId % 3 == 0) {
//這幾位車主不愿意一直等待卤档,所有設(shè)定一個能接受的等待時間
NSUInteger result = dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 8 * carId * NSEC_PER_SEC));
if (result != 0) {//超時,直接離開
NSLog(@"第%ld個車主不等了",carId);
} else {
NSLog(@"第%ld個車主在規(guī)定的時間內(nèi)等到了車位程剥,進(jìn)入停車場",carId);
[NSThread sleepForTimeInterval:10];
dispatch_semaphore_signal(semaphore);
NSLog(@"第%ld個車主離開,有空位了",carId);
}
} else {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"第%ld個車主進(jìn)入停車場",carId);
[NSThread sleepForTimeInterval:10 + i * 10];
dispatch_semaphore_signal(semaphore);
NSLog(@"第%ld個車主離開,有空位了",carId);
}
});
}
}
//運(yùn)行結(jié)果
2018-05-24 12:13:55.959 MultiThreadingDemo[1490:186763] 第3個車主離開,有空位了
2018-05-24 12:13:55.959 MultiThreadingDemo[1490:186860] 第4個車主進(jìn)入停車場
2018-05-24 12:14:05.959 MultiThreadingDemo[1490:186764] 第1個車主離開,有空位了
2018-05-24 12:14:05.959 MultiThreadingDemo[1490:186861] 第5個車主進(jìn)入停車場
2018-05-24 12:14:15.960 MultiThreadingDemo[1490:186766] 第2個車主離開,有空位了
2018-05-24 12:14:15.960 MultiThreadingDemo[1490:186862] 第6個車主在規(guī)定的時間內(nèi)等到了車位劝枣,進(jìn)入停車場
2018-05-24 12:14:25.962 MultiThreadingDemo[1490:186862] 第6個車主離開,有空位了
2018-05-24 12:14:25.962 MultiThreadingDemo[1490:186863] 第7個車主進(jìn)入停車場
2018-05-24 12:14:45.966 MultiThreadingDemo[1490:186860] 第4個車主離開,有空位了
2018-05-24 12:14:45.966 MultiThreadingDemo[1490:186864] 第8個車主進(jìn)入停車場
2018-05-24 12:14:57.961 MultiThreadingDemo[1490:186865] 第9個車主不等了
2018-05-24 12:15:05.964 MultiThreadingDemo[1490:186861] 第5個車主離開,有空位了
2018-05-24 12:15:05.964 MultiThreadingDemo[1490:186866] 第10個車主進(jìn)入停車場
2018-05-24 12:15:45.968 MultiThreadingDemo[1490:186863] 第7個車主離開,有空位了
2018-05-24 12:16:15.972 MultiThreadingDemo[1490:186864] 第8個車主離開,有空位了
2018-05-24 12:16:55.971 MultiThreadingDemo[1490:186866] 第10個車主離開,有空位了
GCD系列
參考資料:
https://blog.csdn.net/liuyang11908/article/details/70757534
http://www.reibang.com/p/2d57c72016c6