使用 GCD 控制线程执行顺序

2018-08-21  本文已影响140人  AprSnow

前言

需求:有三个异步执行的任务ABC任务 C 必须等待任务 A任务 B 执行完毕才执行。

本文分别采用三种方法来实现线程执行顺序的控制,semaphorebarriergroup。详细代码可以参考 WZHWaitThread

Semaphore

执行 dispatch_semaphore_wait 时,如果信号量大于 0,可以继续执行并把信号量减一;如果信号量小于等于 0,线程被阻塞,等待信号量大于 0dispatch_semaphore_signal 释放信号量,使信号量加一。dispatch_semaphore_waitdispatch_semaphore_signal 配合使用可以控制线程的执行。

- (void)waitThreadWithSemaphore {
    dispatch_queue_t currentQueue = dispatch_queue_create("current queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);
    
    dispatch_async(currentQueue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"Thread A %@", [NSThread currentThread]);
        dispatch_semaphore_signal(semaphore);
    });

    dispatch_async(currentQueue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"Thread B %@", [NSThread currentThread]);
        dispatch_semaphore_signal(semaphore);
    });

    dispatch_async(currentQueue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"Thread C %@", [NSThread currentThread]);
        dispatch_semaphore_signal(semaphore);
        dispatch_semaphore_signal(semaphore);
        // dispatch_semaphore_wait 和 dispatch_semaphore_signal 必须成对使用
    });
    
    NSLog(@"Wait Thread Test.");
}

Barrier

dispatch_barrier_async 可以拦截线程的执行,在 dispatch_barrier_async 之前的线程执行完才会执行 dispatch_barrier_async 之后的的线程。这里注意两点:

  1. 在使用栅栏函数时,使用自定义的并行队列才有意义,如果用的是串行队列或者系统提供的全局并发队列,这个栅栏函数的作用等同于一个 dispatch_sync 的作用。

The queue you specify should be a concurrent queue that you create yourself using the dispatch_queue_create function. If the queue you pass to this function is a serial queue or one of the global concurrent queues, this function behaves like the dispatch_sync function.

  1. dispatch_barrier_asyncdispatch_barrier_sync 的区别

dispatch_barrier_sync 需要等待自己的任务结束之后才会继续程序,然后执行后面的任务;
dispatch_barrier_async 将自己的任务插入到 queue 之后,不会等待自己的任务结束,会继续把后面的任务插入到 queue

- (void)waitThreadWithBarrier {
    dispatch_queue_t queue = dispatch_queue_create("current queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"Thread A %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"Thread B %@", [NSThread currentThread]);
    });
    
    dispatch_barrier_sync(queue, ^{
        NSLog(@"barrier %@", [NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        NSLog(@"Thread C %@", [NSThread currentThread]);
    });
    
    NSLog(@"Wait Thread Test In %@", [NSThread currentThread]);
}

Group

dispatch_group 可以把相关的任务归并到一个组内来执行,通过监听组内所有任务的执行情况来做相应处理。待任务组执行完毕时调用 dispatch_group_notify,不会阻塞当前线程。或者 dispatch_group_wait 可以等待组任务完成,会阻塞当前线程,当任务组执行完毕时,才会解除阻塞当前线程。

注意:不要在主线程使用 dispatch_group_wait,如果 group 中如果添加主队列后再使用 dispatch_group_wait 有可能引起死锁。

- (void)waitThreadWithGroup {
    dispatch_queue_t queue = dispatch_queue_create("current queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, queue, ^{
        NSLog(@"Thread A %@", [NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"Thread B %@", [NSThread currentThread]);
    });
    dispatch_group_notify(group, queue, ^{
        NSLog(@"Thread C %@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
        NSLog(@"Wait Thread Test In %@", [NSThread currentThread]);
    });
}
上一篇 下一篇

猜你喜欢

热点阅读