浅谈:如何实现多条线程执行完后再进行其他操作

假设这么一个使用场景,问要大象放进冰箱里。分为几步?

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激活,需要多个接口返回便加上多个等待即可。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 背景 担心了两周的我终于轮到去医院做胃镜检查了!去的时候我都想好了最坏的可能(胃癌),之前在网上查的症状都很相似。...
    Dely阅读 9,296评论 21 42
  • Managing Units of Work(管理工作单位) 调度块允许您直接配置队列中各个工作单元的属性。它们还...
    edison0428阅读 8,092评论 0 1
  • 最近颇花了一番功夫把多线程GCD人的一些用法总结出来,一来帮自己巩固一下知识、二来希望能帮到对这一块还迷茫...
    人活一世阅读 307评论 1 1
  • GCD (Grand Central Dispatch) :iOS4 开始引入,使用更加方便,程序员只需要将任务添...
    池鹏程阅读 1,373评论 0 2
  • 前言“变化的世界,不变的原则”以人类面临的最普遍的几种挑战为例,让我深刻体会到强调原则和解决办法与我们的流行文化的...
    小雪花不是花阅读 867评论 0 6