“这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战”
前言
上一篇我们运行了GCD函数的使用 通过串行队列和并发队列的理解看到了死锁 我们这一篇看一下GCD函数与队列的关系
一.主队列分析
队列分为 串行队列 和 并行队列
- 串行队列:
dispatch_queue_t serial = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL); - 并发队列:
dispatch_queue_t conque = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT); - 主队列:
dispatch_queue_t mainQueue = dispatch_get_main_queue(); - 全局队列:
dispatch_queue_t globQueue =dispatch_get_global_queue(0, 0);
通过bt打印 找到libdispatch-1271.120.2源码 分析GCD
通过libdispatch源码搜索dispatch_get_main_queue
_dispatch_main_q
通过打印主队列找到名称
全局搜索 com.apple.main-thread
因为 .dq_atomic_flags = DQF_WIDTH(1),
.dq_serialnum = 1, 所以是串行队列 下面我们分析为什么
二.串行和并发的底层源码辨识
1.串行队列必然有某些特性 VS 并发队列
串行和并行队列都是通过dispatch_queue_create创建的 下面我们分析一下源码
进入 _dispatch_lane_create_with_target
通过_dispatch_queue_init 这个函数传值
dqai_concurrent ?DISPATCH_QUEUE_WIDTH_MAX : 1 进入_dispatch_queue_init看一下
所以DQF_WIDTH = 1 就为串行队列 跟dq_serialnum=1没有关系
dq_serialnum =os_atomic_inc_orig(&_dispatch_queue_serial_numbers, relaxed)
_dispatch_queue_serial_numbers是什么呢
DISPATCH_QUEUE_SERIAL_NUMBER_INIT是什么呢
下面方法做了优先级处理
串行队列传
NULL的原因 就是当dqai为NULL时 直接返回dqai
三.GCD底层源码继承链
通过bt打印com.apple.root.default-qos
通过libdispatch源码搜索com.apple.root.default-qos
dispatch_queue_t 点击进入
DISPATCH_DECL在源码中对应
#define DISPATCH_DECL(name) \
typedef struct name##_s : public dispatch_object_s {} *name##_t
DISPATCH_DECL(dispatch_queue);
typedef struct dispatch_queue_s : public dispatch_object_s {} *dispatch_queue_t
相当于dispatch_queue_t->dispatch_queue_s->dispatch_object_s->_os_object_s->dispatch_object_t class->objc_class->objc_object
所有的都是
dispatch_object_t这个类型
四.MT和KS面试题
- (void)MTDemo{
while(self.num < 5) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
self.num++;
});
}
NSLog(@"end : %d",self.num); //结果>=5
}
- (void)KSDemo{
for(int i= 0; i<10000; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
self.num++;
});
}
NSLog(@"end : %d",self.num); // <=10000
}
五.GCD的任务执行堆栈(同步)
dispatch_sync的block()到底在哪里调用的 我们查看一下源码
先查看一下_dispatch_Block_invoke是什么
查看一下 _dispatch_sync_f
查看一下
_dispatch_sync_f_inline
加一个符号断点_dispatch_sync_f_slow发现进入了
加一个符号断点_dispatch_sync_function_invoke发现进入了
查看一下
_dispatch_sync_function_invoke_inline
查看一下
_dispatch_client_callout
断点 bt验证探索流程没毛病
六.GCD的任务执行堆栈(异步)
dispatch_async的block()到底在哪里调用的 我们查看一下源码
查看一下
_dispatch_continuation_init
查看一下_dispatch_continuation_init_f
查看一下 _dispatch_continuation_priority_set优先级异步处理
查看一下
_dispatch_continuation_async
查看一下
dx_push
查看一下dq_push queue_global队列
查看一下 _dispatch_root_queue_push
查看一下 _dispatch_root_queue_push_inline
查看一下
_dispatch_root_queue_poke
查看一下
_dispatch_root_queue_poke_slow
查看一下_dispatch_root_queues_init
查看一下_dispatch_root_queues_init_once
查看一下_dispatch_worker_thread2
查看一下_dispatch_root_queue_drain
查看一下_dispatch_continuation_pop_inline
查看一下_dispatch_continuation_invoke_inline
查看一下_dispatch_client_callout
查看一下 dx_invoke
查看一下 do_invoke
查看一下_dispatch_queue_override_invoke
查看一下 _dispatch_continuation_invoke_inline
查看一下_dispatch_client_callout
bt打印