OC底层原理23-GCD分析上

525 阅读2分钟

这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战

前言

上一篇我们运行了GCD函数的使用 通过串行队列和并发队列的理解看到了死锁 我们这一篇看一下GCD函数与队列的关系

一.主队列分析

队列分为 串行队列 和 并行队列

  1. 串行队列:dispatch_queue_t serial = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
  2.   并发队列:dispatch_queue_t conque = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
  3.   主队列:dispatch_queue_t mainQueue = dispatch_get_main_queue();
  4.  全局队列:dispatch_queue_t globQueue =dispatch_get_global_queue(0, 0);

通过bt打印 找到libdispatch-1271.120.2源码 分析GCD

Xnip2021-08-07_23-32-18.jpg

通过libdispatch源码搜索dispatch_get_main_queue

Xnip2021-08-07_23-36-13.jpg

Xnip2021-08-07_23-37-34.jpg

_dispatch_main_q

Xnip2021-08-07_23-39-41.jpg

通过打印主队列找到名称

Xnip2021-08-07_23-43-31.jpg

全局搜索 com.apple.main-thread

Xnip2021-08-07_23-44-34.jpg

因为 .dq_atomic_flags = DQF_WIDTH(1), .dq_serialnum = 1, 所以是串行队列 下面我们分析为什么

二.串行和并发的底层源码辨识

1.串行队列必然有某些特性 VS 并发队列 串行和并行队列都是通过dispatch_queue_create创建的 下面我们分析一下源码

Xnip2021-08-07_23-52-46.jpg

进入 _dispatch_lane_create_with_target

Xnip2021-08-07_23-56-11.jpg

通过_dispatch_queue_init 这个函数传值 dqai_concurrent ?DISPATCH_QUEUE_WIDTH_MAX : 1 进入_dispatch_queue_init看一下

Xnip2021-08-07_23-59-50.jpg

所以DQF_WIDTH = 1 就为串行队列 跟dq_serialnum=1没有关系

dq_serialnum =os_atomic_inc_orig(&_dispatch_queue_serial_numbers, relaxed)

_dispatch_queue_serial_numbers是什么呢

Xnip2021-08-08_00-03-27.jpg

DISPATCH_QUEUE_SERIAL_NUMBER_INIT是什么呢

Xnip2021-08-08_00-03-55.jpg

下面方法做了优先级处理

Xnip2021-08-08_00-09-53.jpg 串行队列传NULL的原因 就是当dqaiNULL时 直接返回dqai Xnip2021-08-08_00-10-13.jpg

三.GCD底层源码继承链

通过bt打印com.apple.root.default-qos

Xnip2021-08-08_00-22-56.jpg

通过libdispatch源码搜索com.apple.root.default-qos

Xnip2021-08-08_00-25-10.jpg

dispatch_queue_t 点击进入

Xnip2021-08-08_00-36-53.jpg

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

Xnip2021-08-08_00-50-36.jpg 所有的都是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_syncblock()到底在哪里调用的 我们查看一下源码

Xnip2021-08-08_01-04-52.jpg

先查看一下_dispatch_Block_invoke是什么

Xnip2021-08-08_01-06-44.jpg

查看一下 _dispatch_sync_f

Xnip2021-08-08_01-07-48.jpg 查看一下 _dispatch_sync_f_inline

Xnip2021-08-08_01-08-39.jpg

加一个符号断点_dispatch_sync_f_slow发现进入了

Xnip2021-08-08_01-11-51.jpg

加一个符号断点_dispatch_sync_function_invoke发现进入了

Xnip2021-08-08_01-15-43.jpg 查看一下 _dispatch_sync_function_invoke_inline Xnip2021-08-08_01-16-10.jpg 查看一下 _dispatch_client_callout

Xnip2021-08-08_01-17-33.jpg

断点 bt验证探索流程没毛病 Xnip2021-08-08_01-19-39.jpg

六.GCD的任务执行堆栈(异步)

dispatch_asyncblock()到底在哪里调用的 我们查看一下源码

Xnip2021-08-08_01-21-37.jpg 查看一下 _dispatch_continuation_init

Xnip2021-08-08_01-23-08.jpg

查看一下_dispatch_continuation_init_f

Xnip2021-08-08_01-24-29.jpg

查看一下 _dispatch_continuation_priority_set优先级异步处理

Xnip2021-08-08_01-25-34.jpg

Xnip2021-08-08_01-28-01.jpg 查看一下_dispatch_continuation_async

Xnip2021-08-08_01-28-47.jpg 查看一下dx_push

Xnip2021-08-08_01-30-32.jpg

查看一下dq_push queue_global队列

Xnip2021-08-08_01-34-18.jpg

查看一下 _dispatch_root_queue_push

Xnip2021-08-08_09-56-37.jpg

查看一下 _dispatch_root_queue_push_inline

Xnip2021-08-08_01-36-56.jpg 查看一下_dispatch_root_queue_poke

Xnip2021-08-08_01-37-42.jpg 查看一下_dispatch_root_queue_poke_slow

Xnip2021-08-08_01-38-16.jpg

查看一下_dispatch_root_queues_init

Xnip2021-08-08_01-39-05.jpg

查看一下_dispatch_root_queues_init_once

Xnip2021-08-08_01-39-46.jpg

Xnip2021-08-08_01-41-00.jpg

查看一下_dispatch_worker_thread2

Xnip2021-08-08_01-41-28.jpg

查看一下_dispatch_root_queue_drain

Xnip2021-08-08_01-43-12.jpg

查看一下_dispatch_continuation_pop_inline

Xnip2021-08-08_01-44-14.jpg

查看一下_dispatch_continuation_invoke_inline

Xnip2021-08-08_01-45-08.jpg

查看一下_dispatch_client_callout

Xnip2021-08-08_01-46-29.jpg

查看一下 dx_invoke

Xnip2021-08-08_10-39-53.jpg

查看一下 do_invoke

Xnip2021-08-08_10-45-00.jpg

查看一下_dispatch_queue_override_invoke

Xnip2021-08-08_10-45-48.jpg

查看一下 _dispatch_continuation_invoke_inline

Xnip2021-08-08_10-47-15.jpg

查看一下_dispatch_client_callout

Xnip2021-08-08_01-46-29.jpg

bt打印

Xnip2021-08-08_01-48-30.jpg