浅谈:如何实现多条线程执行完后再进行其他操作
2017-07-07 本文已影响32人
anjohnlv
假设这么一个使用场景,问要大象放进冰箱里。分为几步?
1、分两拨人分别去找冰箱和大象;
2、找到冰箱后,打开冰箱门,等待大象;
3、找到大象后等待冰箱门打开;
4、都做完之后把大象装进去,关门。
纯洁的我一直这么做:
1、声明一个成员变量
finishAmount
,初始化为0
2、找到冰箱之后尝试去装一次大象,如果发现finishAmount==0
,说明还没找到大象,于是finishAmount++
,之后就return
了。
3、找到冰箱并开门之后尝试去装一次大象,如果发现finishAmount==0
,同上。
4、如果发现如果发现finishAmount==1
,说明另一步已经完成了。就可以开心得装大象了。
@implementation OldJob {
int finishAmount;
}
-(void)putElephantInRefrigerator:(void (^)(NSString *))completion {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self searchRefrigerator];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self searchElephant];
});
}
-(void)searchRefrigerator {
sleep(5);
NSLog(@"找到冰箱了");
[self openRefrigeratorDoor];
}
-(void)openRefrigeratorDoor {
NSLog(@"开门了");
[self everythingIsOk];
}
-(void)searchElephant {
sleep(3);
NSLog(@"找到大象了");
[self everythingIsOk];
}
-(void)everythingIsOk {
if(finishAmount == 0) {
finishAmount++;
return;
}
NSLog(@"everythingIsOk");
}
直到有一天突然想装逼了,我要知道你找冰箱的每一步状态:
@implementation MyJob {
dispatch_semaphore_t semaphore;
dispatch_group_t group;
dispatch_queue_t queue;
}
-(instancetype)init {
self = [super init];
if (self) {
semaphore = dispatch_semaphore_create(0);
group = dispatch_group_create();
queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
}
return self;
}
-(void)putElephantInRefrigerator:(void (^)(NSString *))completion {
dispatch_group_notify(group, queue, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
[self everythingIsOk:completion];
});
dispatch_group_async(group, queue, ^{
[self searchRefrigerator:completion];
});
dispatch_group_async(group, queue, ^{
[self searchElephant];
});
}
-(void)searchRefrigerator:(void (^)(NSString *))completion {
sleep(5);
if (completion) {
completion(@"找到冰箱啦");
}
[self openRefrigeratorDoor:completion];
}
-(void)openRefrigeratorDoor:(void (^)(NSString *))completion {
if (completion) {
completion(@"门打开啦");
}
dispatch_semaphore_signal(semaphore);
}
-(void)searchElephant {
sleep(3);
dispatch_semaphore_signal(semaphore);
}
-(void)everythingIsOk:(void (^)(NSString *))completion {
if (completion) {
completion(@"everythingIsOk");
}
}
利用dispatch_group_notify
的特性,在相同group
全部返回了,才会执行。在这里,如果先执行
dispatch_group_async(group, queue, ^{
[self searchRefrigerator:completion];
});
dispatch_group_async(group, queue, ^{
[self searchElephant];
});
再执行
dispatch_group_notify(group, queue, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
[self everythingIsOk:completion];
});
则可以直接达到预期效果,但是我们在实际的应用场合中,复杂的网络请求往往并不能按照理想的按部就班。于是我们在这加上了dispatch_semaphore_wait
。
如在本例中,dispatch_group_notify
先于dispatch_group_async
调用。调用时发现已没有未执行的dispatch_group_async
,便会直接执行,而不能达到确保其他接口都执行完了再执行的需求。
加上dispatch_semaphore_wait
后,执行时会等待dispatch_semaphore_signal
激活,需要多个接口返回便加上多个等待即可。