iOS 底层探索篇 —— GCD栅栏函数、信号量、调度组和Dispatch_Source

本文深入探讨了iOS中GCD的几个关键概念:栅栏函数用于确保特定任务在其他任务执行完毕后运行,避免线程竞争;信号量用于控制并发,实现同步;调度组保证任务执行顺序;Dispatch_Source则提供低开销的事件处理。通过这些技术,开发者可以更好地管理和协调多线程任务。

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

1. 栅栏函数

1.1 栅栏函数的作用

栅栏函数最直接的作用是 控制任务执行顺序,同步

  • dispatch_barrier_async 前面的任务执行完毕才会来到这里
  • dispatch_barrier_sync 作用相同,但是这个会堵塞线程,影响后面的任务执行
  • 栅栏函数在全局队列中是无效的
  • 非常重要的一点: 栅栏函数只能控制同一并发队列

这里的函数运行状况是,123456起来干是随机打印的,而dispatch_barrier_async里面的函数加载那么多喘口气是一定在456后面运行的。
在这里插入图片描述
如果是dispatch_barrier_sync,那么就会堵塞线程,影响后面的任务执行,也就是说会影响起来干的执行和加载那么多的执行,这两个任务会在栅栏函数执行完后执行,执行顺序不固定。
在这里插入图片描述
如果栅栏函数和其他函数不在同一队列,那么就不会影响其他队列任务的执行
在这里插入图片描述
在这里插入图片描述
如果是全局队列的话,那么栅栏函数也是无效的
在这里插入图片描述
在这里插入图片描述
栅栏函数还能起到的作用。
数组是线程不安全的,这样异步向数组添加元素的话是会崩溃的。在多线程条件下,mArray的地址永远是同一个,在执行过程中,mArray元素的个数不停的变化。在添加元素的时候,需要对mArray进行一个读的操作,然后在进行一个写的操作。而写的操作就会有对新值的retain和对旧值的release。这个时候如果有一个多线程进行同时对一个位置写的操作,也就是对同一时间对同一内存空间进行操作,那么就会不安全就会报出异常。
在这里插入图片描述
但是如果加入栅栏函数的话,就不会崩溃了。
在这里插入图片描述

1.2 栅栏函数的原理

栅栏函数是如何实现的呢?
看到dispatch_barrier_sync会调用_dispatch_barrier_sync_f
在这里插入图片描述
接着跳转_dispatch_barrier_sync_f_inline
在这里插入图片描述
这里来到_dispatch_barrier_sync_f_inline
在这里插入图片描述
然后看到_dispatch_sync_recurse。这里进行死循环递归,确保之前的任务已经清空了,然后进行自己block的调用.
在这里插入图片描述
接着看_dispatch_sync_invoke_and_complete_recurse
在这里插入图片描述
然后来到_dispatch_sync_complete_recurse。这里判断是否存在barrier,如果存在,就调用dx_wake 将队列的任务进行唤起执行,然后才调用_dispatch_lane_non_barrier_complete进行状态的修改。
在这里插入图片描述
查找一下dx_wake 也就是dq_wake。普通的队列是_dispatch_lane_wakeup,全局队列则是_dispatch_root_queue_wakeup。_dispatch_lane_wakeup中如果是barrier形式,就会调用_dispatch_lane_barrier_complete,否则就调用_dispatch_queue_wakeup。而全局队列则没有对barrier进行处理,也就是说barrier对全局队列没有影响。全局队列对栅栏函数不处理的原因是,全局队列不仅仅被我们使用,也被系统使用。如果对栅栏函数进行处理,那么可能影响到系统任务的执行,所以全局队列不对barrier进行处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值