GCD-线程栅栏

GCD的线程栅栏分为同步栅栏(dispatch_barrier_sync)和异步栅栏(dispatch_barrier_async)
同步栅栏:
-同步栅栏中的任务会等之前添加到同一队列的任务都结束后开始按顺序执行。
-同步栅栏的任务会在主线程运行,会阻塞当前代码,等栅栏函数中的任务完成后才会接着执行之后的代码,相当于开启了一个同步任务。
异步栅栏:
-异步栅栏中的任务会等之前添加到同一队列的任务都结束后开始按顺序执行。
-异步栅栏中的任务不在主线程运行,不会阻塞异步栅栏之后主线程的代码。

1.同步栅栏

    dispatch_queue_t queue = dispatch_queue_create("barrierQueue", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 3; i++) {
        dispatch_async(queue, ^{
            sleep(1);
            NSLog(@"栅栏前任务%d 线程%@", i, [NSThread currentThread]);
        });
    }
    NSLog(@"代码经过栅栏前");
    dispatch_barrier_sync(queue, ^{
        NSLog(@"栅栏任务1,线程%@", [NSThread currentThread]);
        sleep(1);
    });
    dispatch_barrier_sync(queue, ^{
        NSLog(@"栅栏任务2,线程%@", [NSThread currentThread]);
        sleep(1);
    });
    NSLog(@"代码通过栅栏");
    for (int i = 0; i < 3; i++) {
        dispatch_async(queue, ^{
            sleep(1);
            NSLog(@"栅栏后任务%d 线程%@", i, [NSThread currentThread]);
        });
    }

运行结果:

2020-02-28 17:07:42.011765+0800 Test[24412:1701334] 代码经过栅栏前
2020-02-28 17:07:42.011890+0800 Test[24412:1701446] 栅栏前任务开始2 线程<NSThread: 0x600000364c80>{number = 5, name = (null)}
2020-02-28 17:07:42.011891+0800 Test[24412:1701439] 栅栏前任务开始0 线程<NSThread: 0x600000364bc0>{number = 3, name = (null)}
2020-02-28 17:07:42.011919+0800 Test[24412:1701445] 栅栏前任务开始1 线程<NSThread: 0x600000364a80>{number = 4, name = (null)}
2020-02-28 17:07:43.014260+0800 Test[24412:1701446] 栅栏前任务结束2 线程<NSThread: 0x600000364c80>{number = 5, name = (null)}
2020-02-28 17:07:43.014260+0800 Test[24412:1701439] 栅栏前任务结束0 线程<NSThread: 0x600000364bc0>{number = 3, name = (null)}
2020-02-28 17:07:43.014301+0800 Test[24412:1701445] 栅栏前任务结束1 线程<NSThread: 0x600000364a80>{number = 4, name = (null)}
2020-02-28 17:07:43.014488+0800 Test[24412:1701334] 栅栏任务1,线程<NSThread: 0x6000003eafc0>{number = 1, name = main}
2020-02-28 17:07:44.014744+0800 Test[24412:1701334] 栅栏任务2,线程<NSThread: 0x6000003eafc0>{number = 1, name = main}
2020-02-28 17:07:45.016132+0800 Test[24412:1701334] 代码通过栅栏
2020-02-28 17:07:46.019509+0800 Test[24412:1701445] 栅栏后任务0 线程<NSThread: 0x600000364a80>{number = 4, name = (null)}
2020-02-28 17:07:46.019552+0800 Test[24412:1701446] 栅栏后任务1 线程<NSThread: 0x600000364c80>{number = 5, name = (null)}
2020-02-28 17:07:46.019567+0800 Test[24412:1701444] 栅栏后任务2 线程<NSThread: 0x600000365400>{number = 6, name = (null)}

观察结果可以看到,主线程的"代码通过栅栏"在栅栏任务结束后才打印,并且栅栏任务所在的线程是主线程,所以同步栅栏会阻塞主线程,同步之后的代码要等到同步栅栏的任务完成后才会去执行。
观察栅栏任务0,1,2和同步栅栏任务1,2可以得出,同步栅栏中的任务要等栅栏前添加到同一队列的任务完成,才会按顺序执行。

2.异步栅栏

    dispatch_queue_t queue = dispatch_queue_create("barrierAsyncQueue", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 3; i++) {
        dispatch_async(queue, ^{
            NSLog(@"栅栏前任务开始%d 线程%@", i, [NSThread currentThread]);
            sleep(1);
            NSLog(@"栅栏前任务结束%d 线程%@", i, [NSThread currentThread]);
        });
    }
    NSLog(@"代码经过栅栏前");
    dispatch_barrier_async(queue, ^{
        NSLog(@"栅栏任务1,线程%@", [NSThread currentThread]);
        sleep(1);
    });
    dispatch_barrier_async(queue, ^{
        NSLog(@"栅栏任务2,线程%@", [NSThread currentThread]);
        sleep(1);
    });
    NSLog(@"代码通过栅栏");
    for (int i = 0; i < 3; i++) {
        dispatch_async(queue, ^{
            NSLog(@"栅栏后任务开始%d 线程%@", i, [NSThread currentThread]);
            sleep(1);
            NSLog(@"栅栏后任务结束%d 线程%@", i, [NSThread currentThread]);
        });
    }

运行结果:

2020-02-28 17:22:31.951608+0800 Test[24630:1724365] 代码经过栅栏前
2020-02-28 17:22:31.951707+0800 Test[24630:1724600] 栅栏前任务开始1 线程<NSThread: 0x600002cde540>{number = 4, name = (null)}
2020-02-28 17:22:31.951745+0800 Test[24630:1724816] 栅栏前任务开始2 线程<NSThread: 0x600002cde600>{number = 5, name = (null)}
2020-02-28 17:22:31.951779+0800 Test[24630:1724590] 栅栏前任务开始0 线程<NSThread: 0x600002c3aa40>{number = 3, name = (null)}
2020-02-28 17:22:31.951923+0800 Test[24630:1724365] 代码通过栅栏
2020-02-28 17:22:32.953949+0800 Test[24630:1724600] 栅栏前任务结束1 线程<NSThread: 0x600002cde540>{number = 4, name = (null)}
2020-02-28 17:22:32.953997+0800 Test[24630:1724816] 栅栏前任务结束2 线程<NSThread: 0x600002cde600>{number = 5, name = (null)}
2020-02-28 17:22:32.954026+0800 Test[24630:1724590] 栅栏前任务结束0 线程<NSThread: 0x600002c3aa40>{number = 3, name = (null)}
2020-02-28 17:22:32.954666+0800 Test[24630:1724590] 栅栏任务1开始,线程<NSThread: 0x600002c3aa40>{number = 3, name = (null)}
2020-02-28 17:22:33.955252+0800 Test[24630:1724590] 栅栏任务1结束,线程<NSThread: 0x600002c3aa40>{number = 3, name = (null)}
2020-02-28 17:22:33.955545+0800 Test[24630:1724590] 栅栏任务2开始,线程<NSThread: 0x600002c3aa40>{number = 3, name = (null)}
2020-02-28 17:22:34.956239+0800 Test[24630:1724590] 栅栏任务2结束,线程<NSThread: 0x600002c3aa40>{number = 3, name = (null)}
2020-02-28 17:22:35.960067+0800 Test[24630:1724816] 栅栏后任务1 线程<NSThread: 0x600002cde600>{number = 5, name = (null)}
2020-02-28 17:22:35.960067+0800 Test[24630:1724600] 栅栏后任务2 线程<NSThread: 0x600002cde540>{number = 4, name = (null)}
2020-02-28 17:22:35.960067+0800 Test[24630:1724590] 栅栏后任务0 线程<NSThread: 0x600002c3aa40>{number = 3, name = (null)}

观察结果可以看到,主线程的"代码通过栅栏"在栅栏任务开始前就打印,并且异步栅栏任务在子线程执行,所以异步栅栏任务不会阻塞栅栏后面主线程的代码。
观察栅栏任务0,1,2和异步栅栏任务1,2可以得出,异步栅栏中的任务要等栅栏前添加到同一队列的任务完成,才会按顺序执行。

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

推荐阅读更多精彩内容

  • 本文内容任务、队列的概念、创建方式任务 + 队列的6种组合的执行方式线程间如何通信dispatch_once、di...
    小秀秀耶阅读 4,610评论 0 9
  • 本文用来介绍 iOS 多线程中 GCD 的相关知识以及使用方法。这大概是史上最详细、清晰的关于 GCD 的详细讲...
    花花世界的孤独行者阅读 3,443评论 0 1
  • 1. 简介 百度百科 Grand Central Dispatch(GCD) 是 Apple 为多核的并行运算提出...
    和风细羽阅读 3,701评论 0 0
  • GCD简介 Grand Central Dispatch (GCD)是Apple开发的一个多核编程的较新的解决方法...
    哦累哇滚筒洗衣机阅读 4,911评论 1 2
  • 前言 GCD是iOS开发中十分重要的多线程方案之一,通过对大神文章的学习,此篇文章为代码的练习和一部分自己学习的总...
    炒河粉儿阅读 3,073评论 0 0