栅栏函数
-
控制任务的执行顺序,导致同步的效果
-
栅栏函数有两种:
dispatch_barrier_async
dispatch_barrier_sync
-
di线程撕裂者spatch_barrier_async
异步栅栏函数拦住的是同一个线程中的任务,并不变量与函数会
阻塞线程 -
dispatch_barrier_sync
同步栅变量的定义栏函数也拦住的是同一个队列中的任务,但会
阻塞线程
全局队列栅栏
在全局队列中使用异步栅栏函数,什么也没有拦住 流程图分析
总结
-
- 栅栏函数可以阻塞当前线程的任务,达到控制任务的效果,但只能在
创建线程池的变量与函数并线程池面试题发队列
中使用
- 栅栏函数可以阻塞当前线程的任务,达到控制任务的效果,但只能在
-
- 栅栏函数也可以在多读单写的场景中使用
-
- 栅栏函数只能在当前线程使用,如果多个线程就会起不到想要的效果
信号量
-
二元信号量
它只有0
和1
两个状态,多元信号量
简变量称信号量
-
GCD
中的信号量disp源码1688atch_semaphore_t
中主要有三个函数:-
dispatch_semaphore_create
:创建信号 -
dispatch_semaphore_wait
:等待信号 -
dispatch_semaphore_signal
:释放信号监控app下载
-
源码解读
dispatch_semaphore_create
- 首先如果信号为小于
0
,则返回一个DISPATCH_BAD_INPUT
类型对象,也就是返回个_Nonnull
- 如果信号
大于等于0
,就会对dispatch_semaphore_t
对象dsema
进行一些赋值,并返回源码编辑器下载dsema
对象
dispatch_semaphore_wait
intptr_t
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout)
{
long value = os_atomic_dec2o(dsema, dsema_value, acquire);
if (likely(value >= 0)) {
return 0;
}
return _dispatch_semaphore_wait_slow(dsema, timeout);
}
复制代码
- 等待信号主要是通过
os_ato变量名mic_dec2o线程撕裂者
函数对信号进行自减
,当源码1688值大于等于0
时返回0
- 当值
小于0
时,会走_dispa源码编程器tch_semaphore_wait_sl变量之间的关系ow
方法
_dispatch_semaph线程的几种状态ore_wait_slow
-
当设置了
timeout(超时线程数是什么时间)
,则会根据类型进行源码之家相关操作,本文使用的是DISPATCH_TIME_FOREVER
,此时调用_dispatch_sema4_wait
进行等待处理:- 这里主要是一个
do-while
循环里队等待信号,当不满足条件后才会跳出循环,所以会出现一个等待的效果
- 这里主要是一个
dispatch监控安装_semaphore_signal
intptr_t
dispatch_semaphore_signal(dispatch_semaphore_t dsema)
{
long value = os_atomic_inc2o(dsema, dsema_value, release);
if (likely(value > 0)) {
return 0;
}
if (unlikely(value == LONG_MIN)) {
DISPATCH_CLIENT_CRASH(value,
"Unbalanced call to dispatch_semaphore_signal()");
}
return _dispatch_semaphore_signal_slow(dsema);
}
复制代码
- 发送信号主要监控可以保存多少天是通过
os_atomic_inc2源码网站o
对信号进行自增
,如果自增后的结果大于0
,就返回0
- 如果
自增后还线程池是小于0
,就会走到_dispatch_semaphore_signal_slow
方法
_dispatch_semaphore_sig源码交易平台nal_slow
intptr_t
_dispatch_semaphore_signal_slow(dispatch_semaphore_t dsema)
{
_dispatch_sema4_create(&dsema->dsema_sema, _DSEMA4_POLICY_FIFO);
_dispatch_sema4_signal(&dsema->dsema_sema, 1);
return 1;
}
- 这里有个
_dispatch_sema4_signal
函数进行缓慢发送信号
调度组
- 调度组最直接的作用就是:
控制任务的执行顺序
,Api
主要有以下几个方法:-
dispatch_group_create
:创建组 -
dispatch_group_async
:进组任务 -
dispatch_group_notify
:组任务执行完毕的通知 -
dispatch_group_enter
:进组 -
dispatch_group_leave
:出组 -
dispatch_group_wa线程数越多越好吗it
:等待组任务时间
-
dispatch_线程数越多越好吗group_async
-
调度组不会阻塞线程
-
- 组任务
执行没有顺序
,相当于异步并发队列线程数是什么
- 组任务
-
- 组任务执行完后才会执行
dispatch_group_notify变量之间的关系
任务
- 组任务执行完后才会执行
dispatch_group_wait
dispatch_group_wait
的作源码之家用是阻塞调度组之外的任务
:
-
- 当等待时间结束时,组任务还没完成,就结束阻塞执行其他任务
-
- 当组任务完成,等待时间还未结束时,会结束监控摄像头品牌排行阻塞执行其他任务
原理分析
dispatch_group监控可以保存多少天_creat监控摄像头
dispatch_group_t
dispatch_group_create(void)
{
return _dispatch_group_create_with_count(0);
}
复制代码
dispatch_group_create
方法会调用_dis监控摄像头品牌排行patch_group_create_with_cou变量泵nt
方法,并传入参数0
static inline dispatch_group_t
_dispatch_group_create_with_count(uint32_t n)
{
dispatch_group_t dg = _dispatch_object_alloc(DISPATCH_VTABLE(group),
sizeof(struct dispatch_group_s));
dg->do_next = DISPATCH_OBJECT_LISTLESS;
dg->do_targetq = _dispatch_get_default_queue(false);
if (n) {
os_atomic_store2o(dg, dg_bits,
(uint32_t)-n * DISPATCH_GROUP_VALUE_INTERVAL, relaxed);
os_atomic_store2o(dg, do_ref_cnt, 1, relaxed); // <rdar://22318411>
}
return dg;
}
复制代码
- 方法的源码编辑器下载核心是创建
d监控系统is源码时代patch_group_t
对象dg
,线程池面试题并对它的do_next
和do_targetq
参数进行赋值,然后调用os_atomic_store2o
进行存储
dispatch_group_enter
void
dispatch_group_enter(dispatch_group_t dg)
{
// The value is decremented on a 32bits wide atomic so that the carry
// for the 0 -> -1 transition is not propagated to the upper 32bits.
uint32_t old_bits = os_atomic_sub_orig2o(dg, dg_bits,
DISPATCH_GROUP_VALUE_INTERVAL, acquire);
uint32_t old_value = old_bits & DISPATCH_GROUP_VALUE_MASK;
if (unlikely(old_value == 0)) {
_dispatch_retain(dg); // <rdar://problem/22318411>
}
if (unlikely(old_value == DISPATCH_GROUP_VALUE_MAX)) {
DISPATCH_CLIENT_CRASH(old_bits,
"Too many nested calls to dispatch_group_enter()");
}
}
复制代码
主要调用os_atomic_su监控家用远程手机b_orig2o
进行自减操作
,也就是由0 -> -1
,这块和线程池面试题信号量的操作很像,但没有wait
的步骤
dispatc变量的定义h_grou线程安全p_leave
void
dispatch_group_leave(dispatch_group_t dg)
{
// The value is incremented on a 64bits wide atomic so that the carry for
// the -1 -> 0 transition increments the generation atomically.
uint64_t new_state, old_state = os_atomic_add_orig2o(dg, dg_state,
DISPATCH_GROUP_VALUE_INTERVAL, release);
uint32_t old_value = (uint32_t)(old_state & DISPATCH_GROUP_VALUE_MASK);
if (unlikely(old_value == DISPATCH_GROUP_VALUE_1)) {
old_state += DISPATCH_GROUP_VALUE_INTERVAL;
do {
new_state = old_state;
if ((old_state & DISPATCH_GROUP_VALUE_MASK) == 0) {
new_state &= ~DISPATCH_GROUP_HAS_WAITERS;
new_state &= ~DISPATCH_GROUP_HAS_NOTIFS;
} else {
// If the group was entered again since the atomic_add above,
// we can't clear the waiters bit anymore as we don't know for
// which generation the waiters are for
new_state &= ~DISPATCH_GROUP_HAS_NOTIFS;
}
if (old_state == new_state) break;
} while (unlikely(!os_atomic_cmpxchgv2o(dg, dg_state,
old_state, new_state, &old_state, relaxed)));
return _dispatch_group_wake(dg, old_state, true);
}
if (unlikely(old_value == 0)) {
DISPATCH_CLIENT_CRASH((uintptr_t)old_value,
"Unbalanced call to dispatch_group_leave()");
}
}
复制代码
通过os_atomic_add_orig2o
进行自增(-1 ~ 0)
得到old_state = 0
DISPATCH_GROUP_VALUE_MASK 0x00000000fffffffcULL
DISPATCH_GROUP_VALUE_1 DISPATCH_GROUP_VALUE_MASK
复制代码
-
-
old_value
等于old_state监控 & DISPATCH_GROUP_变量类型有哪些VALUE_MASK
等于0
,此时old_value != DISPATCH_GROUP_VALUE_1
,再由于判断是unlikely
,所以会进入if判断
-
-
- 由于
DISPATCH_GROUP_VALUE_INTERVAL = 4
,所以此时old_state = 4
,再进入do-while
循环,此时会走else
判断new_state &= ~DISPATCH_GROUP_HAS_NOTIFS= 4 & ~2 = 4
,这时old_state
和new_state
相等,然后跳出循环执行_dispatch_gro变量泵up_wake
方法,也就是唤醒dispatch_group_notify
方法
- 由于
-
- 假如
enter
两次,则old_s监控家用远程手机tate=-1
,加上4后
为3源码编辑器下载
,也就是在do-while
循环时,new_state = old_state = 3
。然后new_state &= ~DISPATCH_GROUP_HAS_NOTIFS = 3 & ~2 = 1
,然后不等与old_state
会再进行循环,当再次进行leave
自增操作后,新的循环判断会走到_dispatch_group_wake
函数进行唤醒
- 假如
dispatch_group_notify
static inline void
_dispatch_group_notify(dispatch_group_t dg, dispatch_queue_t dq,
dispatch_continuation_t dsn)
{
uint64_t old_state, new_state;
dispatch_continuation_t prev;
dsn->dc_data = dq;
_dispatch_retain(dq);
prev = os_mpsc_push_update_tail(os_mpsc(dg, dg_notify), dsn, do_next);
if (os_mpsc_push_was_empty(prev)) _dispatch_retain(dg);
os_mpsc_push_update_prev(os_mpsc(dg, dg_notify), prev, dsn, do_next);
if (os_mpsc_push_was_empty(prev)) {
os_atomic_rmw_loop2o(dg, dg_state, old_state, new_state, release, {
new_state = old_state | DISPATCH_GROUP_HAS_NOTIFS;
if ((uint32_t)old_state == 0) {
os_atomic_rmw_loop_give_up({
return _dispatch_group_wake(dg, new_state, false);
});
}
});
}
}
复制代码
主要是通过os_atomic_r源码之家mw_loop2o
进行do-while
循环判断,知道线程和进程的区别是什么old_state == 0
时就会走_dispatch_group_wake
唤醒,也就是会去走block
执行
- 此时还有一个问题没有解决,就是
dispatch_group_a源码编辑器sync
为什么和进组+出组
效果一样,再来分析变量类型有哪些下源码
dispatch_group_async
void
dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq,
dispatch_block_t db)
{
dispatch_continuation_t dc = _dispatch_continuation_alloc();
uintptr_t dc_flags = DC_FLAG_CONSUME | DC_FLAG_GROUP_ASYNC;
dispatch_qos_t qos;
qos = _dispatch_continuation_init(dc, dq, db, 0, dc_flags);
_dispatch_continuation_group_async(dg, dq, dc, qos);
}
这个函数内容比较熟悉,与异步的函数很像,但此时dc_flags = DC_FLA源码网站G_CONSUME | DC_FLAG_GROUP_ASYNC
,然后走进_disp源码精灵永久兑换码atch_continuation_group_async
函数:
static inline void
_dispatch_continuation_group_async(dispatch_group_t dg, dispatch_queue_t dq,
dispatch_continuation_t dc, dispatch_qos_t qos)
{
dispatch_group_enter(dg);
dc->dc_data = dg;
_dispatch_continuation_async(dq, dc, qos, dc->dc_flags);
}
这里我们看到了dispatch_gro源码1688up_enter
,但是没有看到leave
函数,我猜想肯定在block
执行的地方会执行leave
,不然不能确保组里任务执行完,于是根据监控global
类型的dq_push = _dispatch_root_queue_push
最终找到_dispa源码交易平台tch_continuati线程on_invoke_inline
函数
如果是普通异步类型会走到_dispatch_client_callout
函数,如果是DC_FLAG_GROUP_ASY源码中的图片NC
组类型,会走_dispatch线程_continu变量泵ation_with_group_invoke
函数
static inline void
_dispatch_continuation_with_group_invoke(dispatch_continuation_t dc)
{
struct dispatch_object_s *dou = dc->dc_data;
unsigned long type = dx_type(dou);
if (type == DISPATCH_GROUP_TYPE) {
_dispatch_client_callout(dc->dc_ctxt, dc->dc_func);
_dispatch_trace_item_complete(dc);
dispatch_group_leave((dispatch_group_t)dou);
} else {
DISPATCH_INTERNAL_CRASH(dx_type(dou), "Unexpected object type");
}
}
复制代码
此时,当类型是DISPATCH_GROUP_TYPE
时,就会先执行_dis源码时代patch_client_callout
,然后执行dispatch_group_leave
,至此前面的问题全部解决
信号源类型
-
创建源
dispatch_source_t dispatch_source_create(dispatch_source_type_t type, uintptr_t handle, uintptr_t mask, dispatch_queue_t _Nullable queue); 复制代码
- 第一个参数是
dispatch_source_ty变量之间的关系pe_t
类型的type
,然后handle
和mask
都是u线程和进程的区别是什么intptr_t
类型的,最后要传入一个队列
- 第一个参数是
-
使用方法:
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue()); 复制代码
-
源的类型
dispatch_source_type_t
:-
-
DIS监控安装PATCH_SOURCE_TYPE_DATA_ADD
:用于ADD
合并数据
-
-
-
DISPATCH_SOURCE_TYPE_DATA_OR
:用监控摄像头品牌排行于按位或
合并数据
-
-
-
DISPATCH源码之家_SOURCE_TY源码中的图片PE_DATA_REPLACE
:跟踪
通过调用dispatch_source_merge_data
获得的数据的分派源,新获得的数据值线程将替换
尚未交付给源处理程序 的现有数据值
-
-
-
DISPATCH_变量名SOURCE_TYPE_MACH_SEND
:用于监视Mach端口
的无效名称
通知的调度源,只能发送没有接收权限
-
-
-
DIS源码PATCH_SOURCE_TYPE_MACH_RECV
:用于监视Mach端口
的挂起
消息
-
-
-
DISPATCH_SOURCE_TYPE_MEMORYPRESSURE
:用于监控
系统内存压力变化
-
-
-
DISPATCH_SOURCE_TYPE_PROC
:用于监视外部进程
的事件
-
-
-
DISPATCH_SOURCE_TYPE_RE变量是什么意思AD
:监视
文件描述符以获取可读取的挂起字节变量的定义
的分派源
-
-
-
DISPATCH_SOURCE_TYPE_SIGNAL
:监控当前进程
以获取信号的调度源
-
-
-
DISPATCH_SOURCE_TYPE_TIMER
:基于计时器提交事件
处理程序块的分派源
-
-
-
DISPA监控安装TCH_SOURCE_TYPE_VNODE
:用于监视
文件描述符中定义的事件监控安装
的分派源
-
-
-
DISPATCH_SOURCE_TYPE_WRIT变量是什么意思E
:监视
文件描述符以获取可写入字节
的可用缓冲区空间的分派源。
-
-
定时器
下面使用Dispatch Source
来封装一个定时器源码编辑器
- (void)testTimer {
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, 0);
dispatch_source_set_timer(self.timer, startTime, 1 * NSEC_PER_SEC, 0);
__block int a = 0;
dispatch_source_set_event_handler(self.timer, ^{
a++;
NSLog(@"a 的 值 %d", a);
});
dispatch_resume(self.timer);
self.isRunning = YES;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
if (self.isRunning) {
dispatch_suspend(self.timer);
// dispatch_source_cancel(self.timer);
self.isRunning = NO;
NSLog(@" 中场休息下~ ");
} else {
dispatch_resume(self.timer);
self.isRunning = YES;
NSLog(@" 继续喝~ ");
}
}
-
创建定时器
dispatch_source_create
时,一定要用属性或者实例变量接收
,不然定时线程数是什么器不会执行 -
dispatch_source_set_timer
的第二个参数start
是从什么时候开始,第三个参数in变量是什么意思terval
是时间间隔,leeway
是计时器的纳秒偏差 -
计时器停止有两种:
-
dispatch_resume
:计时器暂停但一直在线,可以唤醒 -
dispatch_so监控家用远程手机urce_can源码网站cel
:计时器释放,执行dispatch_线程池resume
唤醒,线程会崩溃
-