iOS Developer

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

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

上一篇下一篇

猜你喜欢

热点阅读