iOS信號量
信號量的本質(zhì):
信號量的本質(zhì)是數(shù)據(jù)操作鎖, 它本身不具有數(shù)據(jù)交換的功能,而是通過控制其他的通信資源來實現(xiàn)進程間通信,它本身只是一種外部資源的標識懈词。信號量在此過程中負責數(shù)據(jù)操作的互斥蜻势、同步等功能.
信號量的工作原理
由于信號量只能進行兩種操作等待和發(fā)送信號,即P(sv)和V(sv),他們的行為是這樣的:
P(sv):如果sv的值大于零,就給它減1雷滚;如果它的值為零,就掛起該進程的執(zhí)行
V(sv):如果有其他進程因等待sv而被掛起吗坚,就讓它恢復(fù)運行祈远,如果沒有進程因等待sv而掛起,就給它加1.
舉個例子刻蚯,就是 兩個進程共享信號量sv绊含,一旦其中一個進程執(zhí)行了P(sv)操作,它將得到信號量炊汹,并可以進入臨界區(qū)躬充,使sv減1。而第二個進程將被阻止進入臨界區(qū)讨便,因為 當它試圖執(zhí)行P(sv)時充甚,sv為0,它會被掛起以等待第一個進程離開臨界區(qū)域并執(zhí)行V(sv)釋放信號量霸褒,這時第二個進程就可以恢復(fù)執(zhí)行伴找。
信號量的三個函數(shù)是:
dispatch_semaphore_create(long value); // 創(chuàng)建一個semaphore
dispatch_semaphore_signal(dispatch_semaphore_t dsema); // 發(fā)送一個信號
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout); // 等到信號
舉幾個例子,代碼如下:
-(void)dispatch_group_function1
{
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_queue_create("com.dispatch.test", DISPATCH_QUEUE_CONCURRENT), ^{
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.baidu.com"]];
NSURLSessionDownloadTask *task = [[NSURLSession sharedSession] downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// 請求完成废菱,可以通知界面刷新界面等操作
NSLog(@"第一步網(wǎng)絡(luò)請求完成");
// 使信號的信號量+1技矮,這里的信號量本來為0,+1信號量為1(綠燈)
dispatch_semaphore_signal(semaphore);
}];
[task resume];
// 以下還要進行一些其他的耗時操作
NSLog(@"耗時操作1繼續(xù)進行");
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
});
dispatch_group_async(group, dispatch_queue_create("com.dispatch.test", DISPATCH_QUEUE_CONCURRENT), ^{
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.github.com"]];
NSURLSessionDownloadTask *task = [[NSURLSession sharedSession] downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// 請求完成殊轴,可以通知界面刷新界面等操作
NSLog(@"第二步網(wǎng)絡(luò)請求完成");
// 使信號的信號量+1衰倦,這里的信號量本來為0,+1信號量為1(綠燈)
dispatch_semaphore_signal(semaphore);
}];
[task resume];
// 以下還要進行一些其他的耗時操作
NSLog(@"耗時操作2繼續(xù)進行");
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"刷新界面等在主線程的操作");
});
}
首先旁理,默認初始值給的信號量值未0樊零,所以線程1和線程2的執(zhí)行上其實是沒有順序的,但是孽文,由于在這里設(shè)置了dispatch_semaphore_wait驻襟,并且當前的信號量值未0夺艰,所以會堵塞線程,直到執(zhí)行了dispatch_semaphore_signal信號量+1沉衣,才會繼續(xù)執(zhí)行之后的線程操作郁副,打印結(jié)果為:
2019-09-27 15:02:51.420389+0800 CPTestDemo[5253:337990] 耗時操作2繼續(xù)進行
2019-09-27 15:02:51.420414+0800 CPTestDemo[5253:337992] 耗時操作1繼續(xù)進行
2019-09-27 15:02:51.544547+0800 CPTestDemo[5253:338000] 第一步網(wǎng)絡(luò)請求完成
2019-09-27 15:02:53.100889+0800 CPTestDemo[5253:337995] 第二步網(wǎng)絡(luò)請求完成
2019-09-27 15:02:53.101065+0800 CPTestDemo[5253:337950] 刷新界面等在主線程的操作
如果初始值設(shè)置dispatch_semaphore_create(1),又會是怎樣的結(jié)果的
2019-09-27 15:05:34.816451+0800 CPTestDemo[5302:345432] 耗時操作1繼續(xù)進行
2019-09-27 15:05:34.816451+0800 CPTestDemo[5302:345433] 耗時操作2繼續(xù)進行
2019-09-27 15:05:34.926754+0800 CPTestDemo[5302:345437] 第一步網(wǎng)絡(luò)請求完成
2019-09-27 15:05:34.926966+0800 CPTestDemo[5302:345393] 刷新界面等在主線程的操作
2019-09-27 15:05:36.475560+0800 CPTestDemo[5302:345437] 第二步網(wǎng)絡(luò)請求完成
如果初始值設(shè)置dispatch_semaphore_create(2)呢
2019-09-27 15:27:59.737338+0800 CPTestDemo[5587:373223] 耗時操作1繼續(xù)進行
2019-09-27 15:27:59.737338+0800 CPTestDemo[5587:373222] 耗時操作2繼續(xù)進行
2019-09-27 15:27:59.758308+0800 CPTestDemo[5587:373190] 刷新界面等在主線程的操作
2019-09-27 15:27:59.880029+0800 CPTestDemo[5587:373220] 第一步網(wǎng)絡(luò)請求完成
2019-09-27 15:28:01.847547+0800 CPTestDemo[5587:373220] 第二步網(wǎng)絡(luò)請求完成
因為信號量初始值為2厢蒜,線程1和2都會執(zhí)行霞势,由于執(zhí)行完成信號量減為0,但是組中的任務(wù)已經(jīng)執(zhí)行完了斑鸦,所以會接著執(zhí)行dispatch_group_notify愕贡,然后依次是第一步網(wǎng)絡(luò)請求和第二步網(wǎng)絡(luò)請求