IMG_5701.JPG

主队列

  • 队列代表口子宽窄,一次一个也可能一次多个,依赖于线程执行

    1. dispatch_queue_main_t
    2. dispatch_get_main_queue(void)
    3. {
    4. return DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q);
    5. }
  • 断点NSlog行,bt查看堆栈信息,底层为libdispatch库 ```objectivec dispatch_async(dispatch_get_global_queue(0, 0), ^{

    1. NSLog(@"CC 函数分析");

    });

  • thread #2, queue = ‘com.apple.root.default-qos’, stop reason = breakpoint 1.1
    • frame #0: 0x0000000102323d07 001—-函数与队列__29-[ViewController viewDidLoad]_block_invoke(.block_descriptor=0x00000001023270e8) at ViewController.m:25:9 frame #1: 0x000000010c4d2578 libdispatch.dylib_dispatch_call_block_and_release + 12 frame #2: 0x000000010c4d374e libdispatch.dylib_dispatch_client_callout + 8 frame #3: 0x000000010c4d5b96 libdispatch.dylib_dispatch_queue_override_invoke + 1026 frame #4: 0x000000010c4e51b0 libdispatch.dylib_dispatch_root_queue_drain + 351 frame #5: 0x000000010c4e5b0f libdispatch.dylib_dispatch_worker_thread2 + 135 frame #6: 0x000000010c9a6453 libsystem_pthread.dylib_pthread_wqthread + 244 frame #7: 0x000000010c9a5467 libsystem_pthread.dylibstart_wqthread + 15 ```

      底层源码

      dispatch

  • 查看dispatch底层源码

    • 上述DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q)中,dispatch_queue_main_t是类型,_dispatch_main_q是对象
    • 查看_dispatch_main_q底层源码
      • dq_label -> 主队列字符串,比如我们自定义的”com.company.XXXX”,主队列中是”com.apple.main-thread”
      • dq_atomic_flags -> DQF_WIDTH(1)代表串行队列,可以通过下面dispatch_queue_create底层源码验证
      • dq_serialnum = 1 -> 只是一个标识,下面会讲到
        1. struct dispatch_queue_static_s _dispatch_main_q = {
        2. DISPATCH_GLOBAL_OBJECT_HEADER(queue_main),
        3. #if !DISPATCH_USE_RESOLVERS
        4. .do_targetq = _dispatch_get_default_queue(true),
        5. #endif
        6. .dq_state = DISPATCH_QUEUE_STATE_INIT_VALUE(1) |
        7. DISPATCH_QUEUE_ROLE_BASE_ANON,
        8. .dq_label = "com.apple.main-thread",
        9. .dq_atomic_flags = DQF_THREAD_BOUND | DQF_WIDTH(1),
        10. .dq_serialnum = 1,
        11. };

        dispatch_queue_create

  • 我们只需要关注返回值dispatch_queue_t,return _dispatch_trace_queue_create(dq)._dq

  • _dispatch_trace_queue_create,苹果经常开启痕迹抓取,用到了trace函数
  • 主要就是dq,dq是通过_dispatch_object_alloc申请开辟内存得到的,然后调用_dispatch_queue_init构造函数初始化
  • dispatch_queue_create底层源码

    1. Step 1: Normalize arguments (qos, overcommit, tq),优先级相关处理,包括label赋值
    2. Step 2: Initialize the queue

      • 申请内存 -> dispatch_lane_t dq = _dispatch_object_alloc(…)
      • 构造函数初始化 -> _dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER | (dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0));
        • 参数dqai.dqai_concurrent判断是否是并发,如果是传一个WIDTH_MAX,否则传1 -> 验证上述dqf_width(1)代表串行队列 ```objectivec DISPATCH_NOINLINE static dispatch_queue_t _dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa, dispatch_queue_t tq, bool legacy) { dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa); // // Step 1: Normalize arguments (qos, overcommit, tq) // dispatch_qos_t qos = dqai.dqai_qos;

      dispatch_lane_t dq = _dispatch_object_alloc(vtable,

      1. sizeof(struct dispatch_lane_s));

      _dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?

      1. DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
      2. (dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0));

      dq->dq_label = label; dq->dq_priority = _dispatch_priority_make((dispatch_qos_t)dqai.dqai_qos,

      1. dqai.dqai_relpri);

      if (overcommit == dispatchqueue_attr_overcommit_enabled) { dq->dq_priority |= DISPATCH_PRIORITY_FLAG_OVERCOMMIT; } if (!dqai.dqai_inactive) { _dispatch_queue_priority_inherit_from_target(dq, tq); _dispatch_lane_inherit_wlh_from_target(dq, tq); } _dispatch_retain(tq); dq->do_targetq = tq; _dispatch_object_debug(dq, “%s”, __func); return _dispatch_trace_queue_create(dq)._dq; } ```

      _dispatch_queue_init

  • 进一步查看_dispatch_queue_init函数

    • dqf |= DQF_WIDTH(width) ,width为1时,dqf就是串行队列

      1. static inline dispatch_queue_class_t
      2. _dispatch_queue_init(dispatch_queue_class_t dqu, dispatch_queue_flags_t dqf,
      3. uint16_t width, uint64_t initial_state_bits)
      4. {
      5. uint64_t dq_state = DISPATCH_QUEUE_STATE_INIT_VALUE(width);
      6. dispatch_queue_t dq = dqu._dq;
      7. dispatch_assert((initial_state_bits & ~(DISPATCH_QUEUE_ROLE_MASK |
      8. DISPATCH_QUEUE_INACTIVE)) == 0);
      9. if (initial_state_bits & DISPATCH_QUEUE_INACTIVE) {
      10. dq->do_ref_cnt += 2; // rdar://8181908 see _dispatch_lane_resume
      11. if (dx_metatype(dq) == _DISPATCH_SOURCE_TYPE) {
      12. dq->do_ref_cnt++; // released when DSF_DELETED is set
      13. }
      14. }
      15. dq_state |= initial_state_bits;
      16. dq->do_next = DISPATCH_OBJECT_LISTLESS;
      17. dqf |= DQF_WIDTH(width);
      18. os_atomic_store2o(dq, dq_atomic_flags, dqf, relaxed);
      19. dq->dq_state = dq_state;
      20. dq->dq_serialnum =
      21. os_atomic_inc_orig(&_dispatch_queue_serial_numbers, relaxed);
      22. return dqu;
      23. }
    • dq_serialnum只是一个标识, dq->dq_serialnum = os_atomic_inc_orig(&_dispatch_queue_serial_numbers, relaxed)

      • 取地址_dispatch_queue_serial_numbers,其值为17,具体定义如下
        • 1 代表主队列
        • 2 代表mgr_q
        • 3 代表mgr_root_q
        • 4-15代表全局队列 global queues
        • 17代表自定义创建队列 workloop_fallback_q
          1. // skip zero
          2. // 1 - main_q
          3. // 2 - mgr_q
          4. // 3 - mgr_root_q
          5. // 4,5,6,7,8,9,10,11,12,13,14,15 - global queues
          6. // 17 - workloop_fallback_q
          7. // we use 'xadd' on Intel, so the initial value == next assigned
          8. #define DISPATCH_QUEUE_SERIAL_NUMBER_INIT 17

GCD底层源码继承链

  • 无论是主队列还是自定队列,都是用dispatch_queue_t类型来接收
  • dispatch_queue_t -> dispatch_queue_s -> dispatch_object_s -> _os_object_s -> dispatch_object_t
  • 类比class -> objc_class(结构体类型) -> objc_object,所以我们来查看dispatch_queue_s具体结构
  • dispatch_object_s根类是dispatch_object_t

    1. typedef union {
    2. struct _os_object_s *_os_obj;
    3. struct dispatch_object_s *_do;
    4. struct dispatch_queue_s *_dq;
    5. struct dispatch_queue_attr_s *_dqa;
    6. struct dispatch_group_s *_dg;
    7. struct dispatch_source_s *_ds;
    8. struct dispatch_channel_s *_dch;
    9. struct dispatch_mach_s *_dm;
    10. struct dispatch_mach_msg_s *_dmsg;
    11. struct dispatch_semaphore_s *_dsema;
    12. struct dispatch_data_s *_ddata;
    13. struct dispatch_io_s *_dchannel;
    14. } dispatch_object_t DISPATCH_TRANSPARENT_UNION;

    问题补充

  • 以下代码打印结果不固定,但一定是大于等于5

    • 异步全局并发队列进行num自增,多线程对一个值进行+1操作,结果不固定
    • 但跳出while的条件一定是大于等于5,所以结果在大于等于5时打印 ```objectivec
  • (void)MTDemo{ while (self.num < 5) {

    1. dispatch_async(dispatch_get_global_queue(0, 0), ^{
    2. self.num++;
    3. });

    } NSLog(@”end : %d”,self.num); // 0-5 0 } ```

  • 以下代码打印结果同样不固定,但结果一定小于等于10000

    • for循环定值运行10000次,多线程操作,耗时操作,有可能结果未回来,所以结果小于等于10000 ```objectivec
  • (void)KSDemo{

    for (int i= 0; i<10000; i++) {

    1. dispatch_async(dispatch_get_global_queue(0, 0), ^{
    2. self.num++;
    3. });

    } NSLog(@”end : %d”,self.num); // > 10000 } ```

    • atomic虽然保证的读写安全,但不能保证多条线程去多的时候安全,因此要进行加锁处理

路由器类图.jpg

GCD中Block执行流程

dispatch_sync

源码验证

  • dq为队列,work为block,是对block的封装
  • _dispatch_Block_invoke宏定义 ->
  • define _dispatch_Block_invoke(bb) \ ((dispatch_function_t)((struct Block_layout *)bb)->invoke)

    1. void
    2. dispatch_sync(dispatch_queue_t dq, dispatch_block_t work)
    3. {
    4. uintptr_t dc_flags = DC_FLAG_BLOCK;
    5. if (unlikely(_dispatch_block_has_private_data(work))) {
    6. return _dispatch_sync_block_with_privdata(dq, work, dc_flags);
    7. }
    8. _dispatch_sync_f(dq, work, _dispatch_Block_invoke(work), dc_flags);
    9. }
  • _dispatch_sync_f底层进入_dispatch_sync_f_inline,通过符号断点进入到_dispatch_sync_f_slow(经常死锁也在这里)

  • 继续符号断点,调用顺序为_dispatch_sync_function_invoke -> _dispatch_sync_function_invoke_inline -> _dispatch_client_callout ->

    1. static void
    2. _dispatch_sync_f_slow(dispatch_queue_class_t top_dqu, void *ctxt,
    3. dispatch_function_t func, uintptr_t top_dc_flags,
    4. dispatch_queue_class_t dqu, uintptr_t dc_flags)
    5. {
    6. dispatch_queue_t top_dq = top_dqu._dq;
    7. dispatch_queue_t dq = dqu._dq;
    8. if (unlikely(!dq->do_targetq)) {
    9. return _dispatch_sync_function_invoke(dq, ctxt, func);
    10. }
    11. pthread_priority_t pp = _dispatch_get_priority();
    12. struct dispatch_sync_context_s dsc = {
    13. .dc_flags = DC_FLAG_SYNC_WAITER | dc_flags,
    14. .dc_func = _dispatch_async_and_wait_invoke,
    15. .dc_ctxt = &dsc,
    16. .dc_other = top_dq,
    17. .dc_priority = pp | _PTHREAD_PRIORITY_ENFORCE_FLAG,
    18. .dc_voucher = _voucher_get(),
    19. .dsc_func = func,
    20. .dsc_ctxt = ctxt,
    21. .dsc_waiter = _dispatch_tid_self(),
    22. };
    23. _dispatch_trace_item_push(top_dq, &dsc);
    24. __DISPATCH_WAIT_FOR_QUEUE__(&dsc, dq);
    25. if (dsc.dsc_func == NULL) {
    26. // dsc_func being cleared means that the block ran on another thread ie.
    27. // case (2) as listed in _dispatch_async_and_wait_f_slow.
    28. dispatch_queue_t stop_dq = dsc.dc_other;
    29. return _dispatch_sync_complete_recurse(top_dq, stop_dq, top_dc_flags);
    30. }
    31. _dispatch_introspection_sync_begin(top_dq);
    32. _dispatch_trace_item_pop(top_dq, &dsc);
    33. _dispatch_sync_invoke_and_complete_recurse(top_dq, ctxt, func,top_dc_flags
    34. DISPATCH_TRACE_ARG(&dsc));
    35. }
  • _dispatch_client_callout中调用了f(ctxt),对block进行了调用,参数ctxt/dispatch_function_f

    1. void
    2. _dispatch_client_callout(void *ctxt, dispatch_function_t f)
    3. {
    4. _dispatch_get_tsd_base();
    5. void *u = _dispatch_get_unwind_tsd();
    6. if (likely(!u)) return f(ctxt);
    7. _dispatch_set_unwind_tsd(NULL);
    8. f(ctxt);
    9. _dispatch_free_unwind_tsd();
    10. _dispatch_set_unwind_tsd(u);
    11. }

    bt验证

  • 断点block处,bt查看堆栈信息

  • 查看block调用同样为_dispatch_sync_function_invoke -> _dispatch_client_callout

image.png

  1. (lldb) bt
  2. * thread #1, queue = 'com.apple.root.default-qos', stop reason = breakpoint 2.1
  3. * frame #0: 0x0000000100634d07 001---函数与队列`__29-[ViewController viewDidLoad]_block_invoke(.block_descriptor=0x00000001006380e8) at ViewController.m:25:9
  4. frame #1: 0x000000010a7e474e libdispatch.dylib`_dispatch_client_callout + 8
  5. frame #2: 0x000000010a7e8fbc libdispatch.dylib`_dispatch_sync_function_invoke + 127

dispatch_async

源码验证

  • 调用流程,dispatch_async ->
    • _dispatch_continuation_async -> dx_push(宏)-> dq_push,在init.c文件中赋值.dq_push,全局队列.dp_push = _dispatch_root_queue_push

1628159634388.jpg

  • _dispatch_root_queue_push流程

    • _dispatch_root_queue_push_inline -> _dispatch_root_queue_poke -> _dispatch_root_queue_poke_slow -> _dispatch_root_queues_init

      1. void
      2. _dispatch_root_queue_push(dispatch_queue_global_t rq, dispatch_object_t dou,
      3. dispatch_qos_t qos)
      4. {
      5. #if DISPATCH_USE_KEVENT_WORKQUEUE
      6. dispatch_deferred_items_t ddi = _dispatch_deferred_items_get();
      7. if (unlikely(ddi && ddi->ddi_can_stash)) {
      8. dispatch_object_t old_dou = ddi->ddi_stashed_dou;
      9. dispatch_priority_t rq_overcommit;
      10. rq_overcommit = rq->dq_priority & DISPATCH_PRIORITY_FLAG_OVERCOMMIT;
      11. if (likely(!old_dou._do || rq_overcommit)) {
      12. dispatch_queue_global_t old_rq = ddi->ddi_stashed_rq;
      13. dispatch_qos_t old_qos = ddi->ddi_stashed_qos;
      14. ddi->ddi_stashed_rq = rq;
      15. ddi->ddi_stashed_dou = dou;
      16. ddi->ddi_stashed_qos = qos;
      17. _dispatch_debug("deferring item %p, rq %p, qos %d",
      18. dou._do, rq, qos);
      19. if (rq_overcommit) {
      20. ddi->ddi_can_stash = false;
      21. }
      22. if (likely(!old_dou._do)) {
      23. return;
      24. }
      25. // push the previously stashed item
      26. qos = old_qos;
      27. rq = old_rq;
      28. dou = old_dou;
      29. }
      30. }
      31. #endif
      32. #if HAVE_PTHREAD_WORKQUEUE_QOS
      33. if (_dispatch_root_queue_push_needs_override(rq, qos)) {
      34. return _dispatch_root_queue_push_override(rq, dou, qos);
      35. }
      36. #else
      37. (void)qos;
      38. #endif
      39. _dispatch_root_queue_push_inline(rq, dou, dou, 1);
      40. }
  • _dispatch_root_queues_init,其_dispatch_root_queues_init_once参数是一个单例

    1. _dispatch_root_queues_init(void)
    2. {
    3. dispatch_once_f(&_dispatch_root_queues_pred, NULL,
    4. _dispatch_root_queues_init_once);
    5. }
  • _dispatch_root_queues_init_once

    • 先判断了线程状态_dispatch_root_queue_init_pthread_pool,判断可使用线程池
    • 配置工作队列

      1. #if DISPATCH_USE_KEVENT_SETUP
      2. struct pthread_workqueue_config cfg = {
      3. .version = PTHREAD_WORKQUEUE_CONFIG_VERSION,
      4. .flags = 0,
      5. .workq_cb = 0,
      6. .kevent_cb = 0,
      7. .workloop_cb = 0,
      8. .queue_serialno_offs = dispatch_queue_offsets.dqo_serialnum,
      9. #if PTHREAD_WORKQUEUE_CONFIG_VERSION >= 2
      10. .queue_label_offs = dispatch_queue_offsets.dqo_label,
      11. #endif
      12. };
    • 多work进行包装,cfg.workq_cb = _dispatch_worker_thread2

    • _dispatch_worker_thread2 -> _dispatch_root_queue_drain -> _dispatch_continuation_pop_inline -> _dispatch_continuation_invoke_inline -> _dispatch_client_callout
  • qos封装流程,_dispatch_continuation_init -> _dispatch_continuation_init_f -> _dispatch_continuation_priority_set

    1. - **_dispatch_continuation_priority_set 任务优先级封装**
    1. void
    2. dispatch_async(dispatch_queue_t dq, dispatch_block_t work)
    3. {
    4. dispatch_continuation_t dc = _dispatch_continuation_alloc();
    5. uintptr_t dc_flags = DC_FLAG_CONSUME;
    6. dispatch_qos_t qos;
    7. qos = _dispatch_continuation_init(dc, dq, work, 0, dc_flags);
    8. _dispatch_continuation_async(dq, dc, qos, dc->dc_flags);
    9. }

    bt验证

    image.png

  • 异步函数中封装了qos,因为异步函数异步调用,过程无序,任务回调是异步。