栅栏函数

本文深入解析GCD栅栏函数dispatch_barrier_async与dispatch_barrier_sync的使用方法及注意事项,阐述如何利用这两种函数控制多线程任务执行顺序,避免死锁,提升程序效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多线程技术最大限度地使用了多核CPU的性能,也极大地提升了任务执行的效率。但是在很多情况下,我们期待能够在并行的任务中,设置有些任务之间的依赖,而使用栅栏函数就很好的一种实现方式.

1 栅栏函数是个啥?

栅栏函数是GCD提供的用于阻塞分割任务的一组函数。就像其定义一样,其主要作用就是在队列中设置栅栏,来人为干预队列中任务的执行顺序.常用的栅栏函数有两个dispatch_barrier_asyncdispatch_barrier_sync.

  • dispatch_barrier_async:用于提交异步执行栅栏函数块任务,并立即返回.所以该函数不会阻塞线程,只会阻塞任务执行。栅栏函数提交之后并不会立即执行,而是会直接返回。等待在栅栏函数之前提交的任务都执行完成之后,栅栏函数任务会自动执行,在栅栏函数之后提交的任务必须在栅栏函数执行完成之后才会执行.
  • dispatch_barrier_sync:用于提交同步执行栅栏函数块任务,并不会立即返回,需要等待栅栏函数提交的任务执行完毕之后才会返回。与dispatch_barrier_async不同,由于该函数需要同步执行,在该栅栏函数任务执行完成之前,函数不会返回,所以此时后边的任务都会被阻塞.

1.2 栅栏函数可以干嘛?

假设我们有三个任务task 001-003,要求task 001 task 002顺序不定,task 003 需要在task 001 和 task 002执行完成之后才可以执行,使用dispatch_barrier_async:

    dispatch_queue_t queue = dispatch_queue_create("com.queueDemo", 0);
    dispatch_async(queue, ^{
        NSLog(@"task 001 --- %@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"task 002 --- %@", [NSThread currentThread]);
    });
    dispatch_barrier_async(queue, ^{
        NSLog(@"task 003 --- %@", [NSThread currentThread]);
    });
    NSLog(@"task 004 --- %@", [NSThread currentThread]);

输出结果为:
task 004 --- <NSThread: 0x282c34cc0>{number = 1, name = main}
task 001 --- <NSThread: 0x282c6c540>{number = 3, name = (null)}
task 002 --- <NSThread: 0x282c6c540>{number = 3, name = (null)}
task 003 --- <NSThread: 0x282c6c540>{number = 3, name = (null)}

而如果使用dispatch_barrier_sync:

    dispatch_queue_t queue = dispatch_queue_create("com.queueDemo", 0);
    dispatch_async(queue, ^{
        NSLog(@"task 001 --- %@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"task 002 --- %@", [NSThread currentThread]);
    });
    dispatch_barrier_sync(queue, ^{
        NSLog(@"task 003 --- %@", [NSThread currentThread]);
    });
    NSLog(@"task 004 --- %@", [NSThread currentThread]);

输出结果:(task 001 task 002随机, task 003在任务task 001 task 002执行完成之后才能执行)
task 001 --- <NSThread: 0x280a132c0>{number = 3, name = (null)}
task 002 --- <NSThread: 0x280a132c0>{number = 3, name = (null)}
task 003 --- <NSThread: 0x280a46e80>{number = 1, name = main}
task 004 --- <NSThread: 0x280a46e80>{number = 1, name = main}

对比之后,不难发现:

  • dispatch_barrier_sync和dispatch_barrier_async都可以实现需求;
  • dispatch_barrier_async只是改变了指定任务的执行顺序,但是并不阻塞线程;而dispatch_barrier_sync不仅改变了任务的执行顺序,而且还会阻塞后续任务的执行,无论是放在那个队列中,后续任务需要等待同步栅栏函数返回才能执行.

1.3 使用栅栏函数需要注意什么?

栅栏函数在需要控制任务之间的依赖关系时,非常用有用,但是需要注意:

  • 两个函数中的queue参数不能为NULL,并且需要是自己使用dispatch_queue_create创建出来的。如果你使用了串行队列或者全局队列,dispatch_barrier_async相当于dispatch_asyn,而dispatch_barrier_sync相当于dispatch_sync.
  • 跟所有的串行队列一样,向串行队列中添加任务,要防止在串行队类中堵塞线程导致的死锁.例如:
    dispatch_queue_t queue = dispatch_queue_create("com.supportHongKongPolice", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        dispatch_async(queue, ^{
            NSLog(@"task 001");
        });
        dispatch_barrier_sync(queue, ^{
            NSLog(@"task 002");
        });
        NSLog(@"task 003");
    });

由于第一个功能块中的任务是同步加入到队列的,所以再向队列中添加栅栏函数就会导致,相互等待资源导致的死锁.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值