GCD全解-dispatch_barrier_sync/async-栅栏函数

简介: GCD全解-dispatch_barrier_sync/async-栅栏函数

前言


应用需求:假设有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 ====================


睡眠0.5秒第2次打印:


2021-02-22 10:40:19.890124+0800 TestDemo[17585:9037449] ======================= Before 11
2021-02-22 10:40:19.890177+0800 TestDemo[17585:9037449] ======================= Before 22
2021-02-22 10:40:19.890200+0800 TestDemo[17585:9037449] ======================= Before 33
2021-02-22 10:40:19.890212+0800 TestDemo[17585:9038004] 11 ====================
2021-02-22 10:40:19.890220+0800 TestDemo[17585:9037449] ======================= Before 44
2021-02-22 10:40:19.890237+0800 TestDemo[17585:9038004] 22 ====================
2021-02-22 10:40:19.890252+0800 TestDemo[17585:9037701] 33 ====================
2021-02-22 10:40:19.890590+0800 TestDemo[17585:9037449] In sync barrier =======
2021-02-22 10:40:19.890691+0800 TestDemo[17585:9037449] ======================= After 11
2021-02-22 10:40:19.890810+0800 TestDemo[17585:9037449] ======================= After 22
2021-02-22 10:40:19.890834+0800 TestDemo[17585:9037701] 44 ====================
2021-02-22 10:40:19.890918+0800 TestDemo[17585:9037449] ======================= After 33
2021-02-22 10:40:19.890948+0800 TestDemo[17585:9037925] 55 ====================


睡眠1秒:


2021-02-22 10:46:16.967080+0800 TestDemo[17596:9039511] ======================= Before 11
2021-02-22 10:46:16.967159+0800 TestDemo[17596:9039511] ======================= Before 22
2021-02-22 10:46:16.967188+0800 TestDemo[17596:9039511] ======================= Before 33
2021-02-22 10:46:16.967214+0800 TestDemo[17596:9039511] ======================= Before 44
2021-02-22 10:46:17.971862+0800 TestDemo[17596:9039717] 22 ====================
2021-02-22 10:46:17.971862+0800 TestDemo[17596:9039707] 33 ====================
2021-02-22 10:46:17.971862+0800 TestDemo[17596:9040111] 11 ====================
2021-02-22 10:46:18.973297+0800 TestDemo[17596:9039511] In sync barrier =======
2021-02-22 10:46:18.973754+0800 TestDemo[17596:9039511] ======================= After 11
2021-02-22 10:46:18.974047+0800 TestDemo[17596:9039511] ======================= After 22
2021-02-22 10:46:18.974258+0800 TestDemo[17596:9039511] ======================= After 33
2021-02-22 10:46:19.978829+0800 TestDemo[17596:9040111] 44 ====================
2021-02-22 10:46:19.979040+0800 TestDemo[17596:9039717] 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 =======================


睡眠0.5秒时第2次打印:


2021-02-22 10:28:46.768469+0800 TestDemo[17561:9033089] =========================== Before 111
2021-02-22 10:28:46.768525+0800 TestDemo[17561:9033089] =========================== Before 222
2021-02-22 10:28:46.768548+0800 TestDemo[17561:9033313] 111 =======================
2021-02-22 10:28:46.768556+0800 TestDemo[17561:9033089] =========================== Before 333
2021-02-22 10:28:46.768594+0800 TestDemo[17561:9033089] =========================== Before 444
2021-02-22 10:28:46.768599+0800 TestDemo[17561:9033536] 222 =======================
2021-02-22 10:28:46.768635+0800 TestDemo[17561:9033089] =========================== After 111
2021-02-22 10:28:46.768691+0800 TestDemo[17561:9033313] 333 =======================
2021-02-22 10:28:46.768728+0800 TestDemo[17561:9033089] =========================== After 222
2021-02-22 10:28:46.768900+0800 TestDemo[17561:9033089] =========================== After 333
2021-02-22 10:28:46.769484+0800 TestDemo[17561:9033313] In async barrier ==========
2021-02-22 10:28:46.769584+0800 TestDemo[17561:9033313] 444 =======================
2021-02-22 10:28:46.769607+0800 TestDemo[17561:9033778] 555 =======================


睡眠1秒时:


2021-02-22 10:21:54.511690+0800 TestDemo[17540:9030197] =========================== Before 111
2021-02-22 10:21:54.511790+0800 TestDemo[17540:9030197] =========================== Before 222
2021-02-22 10:21:54.511820+0800 TestDemo[17540:9030197] =========================== Before 333
2021-02-22 10:21:54.511849+0800 TestDemo[17540:9030197] =========================== Before 444
2021-02-22 10:21:54.511874+0800 TestDemo[17540:9030197] =========================== After 111
2021-02-22 10:21:54.511899+0800 TestDemo[17540:9030197] =========================== After 222
2021-02-22 10:21:54.511922+0800 TestDemo[17540:9030197] =========================== After 333
2021-02-22 10:21:55.516901+0800 TestDemo[17540:9030520] 111 =======================
2021-02-22 10:21:55.516901+0800 TestDemo[17540:9030427] 222 =======================
2021-02-22 10:21:55.516916+0800 TestDemo[17540:9030467] 333 =======================
2021-02-22 10:21:56.522624+0800 TestDemo[17540:9030520] In async barrier ==========
2021-02-22 10:21:57.523760+0800 TestDemo[17540:9030427] 555 =======================
2021-02-22 10:21:57.528231+0800 TestDemo[17540:9030520] 444 =======================


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函数。


相关文章
|
6月前
|
算法 C++ 开发者
【C++ 20 并发工具 std::barrier】掌握并发编程:深入理解C++的std::barrier
【C++ 20 并发工具 std::barrier】掌握并发编程:深入理解C++的std::barrier
245 0
|
6月前
并发编程之的await和signal等方法的详细解析
并发编程之的await和signal等方法的详细解析
32 0
|
6月前
|
API 调度 iOS开发
多线程和异步编程:什么是 GCD(Grand Central Dispatch)?如何在 iOS 中使用 GCD?
多线程和异步编程:什么是 GCD(Grand Central Dispatch)?如何在 iOS 中使用 GCD?
70 1
|
12月前
|
vr&ar Swift
大师学SwiftUI第9章Part 1 - 异步并发之Task、Async、Await和错误
苹果系统借助现代处理器的多核可同步执行多条代码,提升同一时间内程序所能执行的任务。例如,一段代码从网上下载文件,另一段代码可以在屏幕上显示进度。此时,我们不能等待第一个执行完后再执行第二个,而必须要同步执行这两个任务。
169 0
|
图形学
UnityMainThreadDispatcher.Instance().Enqueue运行原理
UnityMainThreadDispatcher.Instance().Enqueue运行原理
552 1
|
前端开发 Go C++
C++并发与多线程(四)async、future、packaged_task、promise、shared_future(上)
C++并发与多线程(四)async、future、packaged_task、promise、shared_future(上)
110 0
|
前端开发 C++ 容器
C++并发与多线程(四)async、future、packaged_task、promise、shared_future(下)
C++并发与多线程(四)async、future、packaged_task、promise、shared_future(下)
|
安全 Java C++
JUC在深入面试题——三种方式实现线程等待和唤醒(wait/notify,await/signal,LockSupport的park/unpark)
JUC在深入面试题——三种方式实现线程等待和唤醒(wait/notify,await/signal,LockSupport的park/unpark)
216 1
JUC在深入面试题——三种方式实现线程等待和唤醒(wait/notify,await/signal,LockSupport的park/unpark)
|
iOS开发
iOS多线程的初步研究-- dispatch同步
GCD提供两种方式支持dispatch队列同步,即dispatch组和信号量。
179 0
GCD全解-dispatch_after/dispatch_time-t延迟操作
GCD全解-dispatch_after/dispatch_time-t延迟操作
329 0