GCD 信号量使用记录
需求:
现在有一个页面,有A, B, C 3个网络请求。A, B是非必须,C是必须,所有请求完毕之后要刷新tableView。
这里当然可以使用异步并发,每个请求的成功或者失败中刷新tableView。
如果要用信号量来控制呢?顺便复习一遍吧。
信号量(Semaphore)是多线程环境下的一种保护设施,可以用来保证两个或多个关键代码不被并发调用。
在进入一个关键代码段之前,线程必须获取一个信号量。一旦执行完毕,该线程就会释放信号量。等待下一个信号量被发送,线程才能继续获取到新信号量并再次执行关键代码段。
一个停车场,只能容下5辆车。这时候,来了6辆车。只有前5辆能进去。第6辆车等待,当有一辆车离开停车场时,才能进入。
这里,
想进停车场 —— 创建信号,
当前有车位 ,领卡进场 —— 发信号,
当前无车位,排队等卡 —— 等信号,
离开停车场 —— 销毁信号。
dispatch_semaphore_create(long value); //!< 创建信号量
dispatch_semaphore_signal(dispatch_semaphore_t dsema); //!< 发送信号量 +1
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout); //!< 等待信号量 -1
作者:QiShare
链接:https://www.jianshu.com/p/0ae764495c9b
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
当信号量为<0时就会阻塞线程,>=0时就继续走。发送信号量 +1 &
等待信号量 -1 是成对出现的
所以 dispatch_semaphore_create(?)函数指定信号量,看情况,一般是指定0
测试代码:
-(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(@"第一步网络请求完成");
// 使信号的信号量+1,这里的信号量本来为0,+1信号量为1(绿灯)
dispatch_semaphore_signal(semaphore);
}];
[task resume];
// 以下还要进行一些其他的耗时操作
NSLog(@"耗时操作继续进行%@",[NSThread currentThread]);
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(@"第二步网络请求完成");
// 使信号的信号量+1,这里的信号量本来为0,+1信号量为1(绿灯)
dispatch_semaphore_signal(semaphore);
}];
[task resume];
// 以下还要进行一些其他的耗时操作
NSLog(@"耗时操作继续进行%@",[NSThread currentThread]);
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"刷新界面等在主线程的操作");
});
}
打印信息:
2020-03-25 11:43:16.034584+0800 GCD信号量Demo[14407:221514] 耗时操作继续进行<NSThread: 0x6000011f9a00>{number = 5, name = (null)}
2020-03-25 11:43:16.034584+0800 GCD信号量Demo[14407:221513] 耗时操作继续进行<NSThread: 0x6000011d8400>{number = 6, name = (null)}
2020-03-25 11:43:16.138100+0800 GCD信号量Demo[14407:221516] 第一步网络请求完成
2020-03-25 11:43:22.544131+0800 GCD信号量Demo[14407:221515] 第二步网络请求完成
2020-03-25 11:43:22.544268+0800 GCD信号量Demo[14407:221068] 刷新界面等在主线程的操作
还有一种方法,设置依赖关系,这里我担心的就是,如果A,B请求出了问题,或者失败了,那C请求还会不会继续呢?
参考https://www.cnblogs.com/tryFighting/p/8178376.html
NSOperationQueue * queue = [[NSOperationQueue alloc] init]; NSBlockOperation * op1 = [NSBlockOperation blockOperationWithBlock:^{ //block队列1 [self _fetchBannerImageVoList]; }]; NSBlockOperation * op2 = [NSBlockOperation blockOperationWithBlock:^{ //block队列2 [self _fetchRemindData]; }]; NSBlockOperation * op3 = [NSBlockOperation blockOperationWithBlock:^{ //block队列3 [self _fetchMixArticleVideoData]; }]; [op2 addDependency:op1]; [op3 addDependency:op2]; [queue addOperation:op1]; [queue addOperation:op2]; [queue addOperation:op3];