dispatch_barrier_sync/async-栅栏函数

106 阅读5分钟

1、前言

应用需求:假设有4个任务{1,2,3,4},执行完前2个再执行后2个

这里我们用到栅栏函数dispatch_barrier_(a)sync,(也可以用队列组),我们要注意的是不能使用全局并发队列(系统提供给我们的)否则会散失栅栏函数的意义。

函数说明

# 栅栏函数仅与并发队列(DISPATCH_QUEUE_CONCURRENT)有效,

/** 同步执行,栅栏效果仅对队列里面的代码有效
* @param queue 自定义并发队列
* @param block 代码块回调
*/
void dispatch_barrier_sync(dispatch_queue_t queue, DISPATCH_NOESCAPE dispatch_block_t block);

/** 异步执行,栅栏效果仅对队列里面的代码有效
* @param queue 自定义并发队列
* @param block 代码块回调
*/
void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);

2、同步栅栏函数:dispatch_barrier_sync

- (void)testCustomBarrierSync {
    dispatch_queue_t currentQueue = dispatch_queue_create("barrierSyncQueue", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"======================= Before 11");
    dispatch_async(currentQueue, ^{
        sleep(0.1);
        NSLog(@"11 =======================");
    });
    NSLog(@"======================= Before 22");
    dispatch_async(currentQueue, ^{
        sleep(0.1);
        NSLog(@"22 =======================");
    });
    NSLog(@"======================= Before 33");
    dispatch_async(currentQueue, ^{
        sleep(0.1);
        NSLog(@"33 ==========");
    });
    NSLog(@"======================= Before 44");
    dispatch_barrier_sync(currentQueue, ^{
        sleep(0.1);
        NSLog(@"In sync barrier =======");
    });
    NSLog(@"======================= After 11");

    dispatch_async(currentQueue, ^{
        sleep(0.1);
        NSLog(@"44 =======================");
    });
    NSLog(@"======================= After 22");
    dispatch_async(currentQueue, ^{
        sleep(0.1);
        NSLog(@"55 =======================");
    });
    NSLog(@"======================= After 33");
}

打印结果:

睡眠0.5秒第1次打印:

2021-02-22 10:05:05.079629+0800 TestDemo[17503:9024036] ======================= Before 11
2021-02-22 10:05:05.079691+0800 TestDemo[17503:9024036] ======================= Before 22
2021-02-22 10:05:05.079699+0800 TestDemo[17503:9024273] 11 ====================
2021-02-22 10:05:05.079737+0800 TestDemo[17503:9024036] ======================= Before 33
2021-02-22 10:05:05.079742+0800 TestDemo[17503:9024445] 22 ====================
2021-02-22 10:05:05.079813+0800 TestDemo[17503:9024036] ======================= Before 44
2021-02-22 10:05:05.079837+0800 TestDemo[17503:9024456] 33 ====================
2021-02-22 10:05:05.080298+0800 TestDemo[17503:9024036] In sync barrier =======
2021-02-22 10:05:05.080404+0800 TestDemo[17503:9024036] ======================= After 11
2021-02-22 10:05:05.080542+0800 TestDemo[17503:9024036] ======================= After 22
2021-02-22 10:05:05.080552+0800 TestDemo[17503:9024446] 44 ====================
2021-02-22 10:05:05.080770+0800 TestDemo[17503:9024036] ======================= After 33
2021-02-22 10:05:05.080779+0800 TestDemo[17503:9024273] 55 ====================

结论:
需要等待栅栏执行完才会执行栅栏后面的任务,甚至包括队列之外的函数。

2、异步栅栏函数:dispatch_barrier_async

- (void)testCustomBarrierAsync {
    dispatch_queue_t currentQueue = dispatch_queue_create("barrierAsyncQueue", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"=========================== Before 111");
    dispatch_async(currentQueue, ^{
        sleep(0.5);
        NSLog(@"111 =======================");
    });
    NSLog(@"=========================== Before 222");
    dispatch_async(currentQueue, ^{
        sleep(0.5);
        NSLog(@"222 =======================");
    });
    NSLog(@"=========================== Before 333");
    dispatch_async(currentQueue, ^{
        sleep(0.5);
        NSLog(@"333 =======================");
    });
    NSLog(@"=========================== Before 444");
    dispatch_barrier_async(currentQueue, ^{
        sleep(0.5);
        NSLog(@"In async barrier ==========");
    });
    NSLog(@"=========================== After 111");

    dispatch_async(currentQueue, ^{
        sleep(0.5);
        NSLog(@"444 =======================");
    });
    NSLog(@"=========================== After 222");
    dispatch_async(currentQueue, ^{
        sleep(0.5);
        NSLog(@"555 =======================");
    });
    NSLog(@"=========================== After 333");
}


睡眠0.5秒时第1次打印:

2021-02-22 10:27:54.280318+0800 TestDemo[17561:9033089] =========================== Before 111
2021-02-22 10:27:54.280383+0800 TestDemo[17561:9033089] =========================== Before 222
2021-02-22 10:27:54.280400+0800 TestDemo[17561:9033430] 111 =======================
2021-02-22 10:27:54.280411+0800 TestDemo[17561:9033089] =========================== Before 333
2021-02-22 10:27:54.280433+0800 TestDemo[17561:9033430] 222 =======================
2021-02-22 10:27:54.280437+0800 TestDemo[17561:9033089] =========================== Before 444
2021-02-22 10:27:54.280457+0800 TestDemo[17561:9033303] 333 =======================
2021-02-22 10:27:54.280490+0800 TestDemo[17561:9033089] =========================== After 111
2021-02-22 10:27:54.280505+0800 TestDemo[17561:9033303] In async barrier ==========
2021-02-22 10:27:54.280682+0800 TestDemo[17561:9033089] =========================== After 222
2021-02-22 10:27:54.280811+0800 TestDemo[17561:9033089] =========================== After 333
2021-02-22 10:27:54.281040+0800 TestDemo[17561:9033303] 444 =======================
2021-02-22 10:27:54.281062+0800 TestDemo[17561:9033430] 555 =======================

4、总结分析 1、现象:dispatch_barrier_sync 需要等待栅栏执行完才会执行栅栏后面的任务,而dispatch_barrier_async 无需等待栅栏执行完,会继续往下走(保留在队列里)。 2、原因:同步栅栏执行的任务在同一个线程中,而异步栅栏执行队列任务时,另外开辟了一个子线程,独立存在。 4、共同点:a、等待在它前面插入队列的任务先执行完。b、等待他们自己的任务执行完再执行后面的任务。

5、栅栏函数 与 自定义并发队列 1、栅栏函数仅对自定义并发队列(DISPATCH_QUEUE_CONCURRENT)才会有栅栏的作用。

dispatch_queue_t queue = dispatch_queue_create("zm", DISPATCH_QUEUE_CONCURRENT);

2、另外,全局并发队列是系统创建,苹果有时候会在全局并发队列中处理它自有任务。使用栅栏函数阻塞全局并发队列无效。 3、针对dispatch_barrier_sync 如果你传入的是串行或全局并发队列 则它的作用和 dispatch_sync 一样; 如果是 dispatch_barrier_async 则它的作用和 dispatch_async一样。

4、官方说明:栅栏函数的队列创建务必使用 dispatch_queue_create 函数创建的并发队列。如果传递给此函数的队列是串行队列或全局并发队列之一,则此函数的行为类似于dispatch_sync函数。