美文网首页
GCD分析(上)

GCD分析(上)

作者: 浅墨入画 | 来源:发表于2021-09-11 19:49 被阅读0次

GCD简介

GCD全称Grand Central Dispatch,是纯 C 语言实现,提供了非常多强大的函数。主要作用是将任务添加到队列,并且指定执行任务的函数

GCD的优势
  • GCD 是苹果公司为多核的并行运算提出的解决方案
  • GCD 会自动利用更多的CPU内核(比如双核、四核)
  • GCD 会自动管理线程的生命周期(创建线程、调度任务、销毁线程) 程序员只需要告诉 GCD 想要执行什么任务,不需要编写任何线程管理代码
GCD基础写法
/**
 * 还原最基础的写法很重要,帮助我们更好的理解GCD的作用 -> 
   将任务添加到队列,并且指定执行任务的函数
 */
- (void)syncTest{
    // 任务块
    dispatch_block_t block = ^{
        NSLog(@"hello GCD");
    };
    //制定任务的队列 -> 串行队列
    dispatch_queue_t queue = dispatch_queue_create("com.lg.cn", NULL);
    // 函数
    dispatch_async(queue, block);
}
函数

任务使用 block 封装,任务的 block 没有参数也没有返回值
执行任务的函数

  • 异步 dispatch_async
  1. 不用等待当前语句执行完毕,就可以执行下一条语句
  2. 会开启线程执行 block 的任务
  3. 异步是多线程的代名词
  • 同步 dispatch_sync
  1. 必须等待当前语句执行完毕,才会执行下一条语句
  2. 不会开启线程
  3. 在当前执行 block 的任务
队列

队列也是一种线性表,它的特性是先进先出(FIFO),插入在一端删除在另一端。就像排队一样,刚来的人入队(push)要排在队尾(rear),每次出队(pop)的都是队首(front)的人。

队列 函数与队列
下面我们来分析几道面试题
  • 面试题一
- (void)textDemo1 {
    // 当前是一个并发队列
    dispatch_queue_t queue = dispatch_queue_create("cooci", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"1");
    dispatch_async(queue, ^{
        NSLog(@"2");
        dispatch_sync(queue, ^{
            NSLog(@"3");
        });
        NSLog(@"4");
    });
    NSLog(@"5");
}

// 打印结果 1 5 2 3 4
  • 面试题二
- (void)textDemo2 {
    // 同步队列
    dispatch_queue_t queue = dispatch_queue_create("cooci", NULL);
    NSLog(@"1");
    // 异步函数
    dispatch_async(queue, ^{
        NSLog(@"2");
        // 同步
        dispatch_sync(queue, ^{
            NSLog(@"3");
        });
        NSLog(@"4");
    });
    NSLog(@"5");
}

// 死锁产生崩溃

异步函数代码块中添加了三个任务

  1. NSLog(@"2");
  2. dispatch_sync(queue, ^{
    NSLog(@"3");
    });
  3. NSLog(@"4");

queue是一个串行队列,NSLog(@"3");是在任务NSLog(@"4");之后
同步函数代码块会堵塞NSLog(@"4");执行,
NSLog(@"3");会堵塞同步函数代码块会执行,
NSLog(@"4");又会堵塞NSLog(@"3");执行,最终形成死锁

删除NSLog(@"4");代码,还会产生死锁吗?

- (void)textDemo2 {
    // 同步队列
    dispatch_queue_t queue = dispatch_queue_create("cooci", NULL);
    NSLog(@"1");
    // 异步函数
    dispatch_async(queue, ^{
        NSLog(@"2");
        // 同步
        dispatch_sync(queue, ^{
            NSLog(@"3");
        });
    });
    NSLog(@"5");
}

// 运行产生死锁崩溃

异步函数代码块中添加了两个任务

  1. NSLog(@"2");
  2. dispatch_sync(queue, ^{
    NSLog(@"3");
    });

同步函数代码块会堵塞异步函数代码块执行,
NSLog(@"3");会堵塞同步函数代码块会执行,
异步函数代码块又会堵·NSLog(@"3");执行,最终形成死锁

最终本质是同步函数代码块异步函数代码块产生堵塞,形成死锁

  • 面试题三
- (void)wbinterDemo{
    // 串行队列
    dispatch_queue_t queue = dispatch_queue_create("com.lg.cooci.cn", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"1");
    });
    dispatch_async(queue, ^{
        NSLog(@"2");
    });

    dispatch_sync(queue, ^{ NSLog(@"3"); });
    
    NSLog(@"0");

    dispatch_async(queue, ^{
        NSLog(@"7");
    });
    dispatch_async(queue, ^{
        NSLog(@"8");
    });
    dispatch_async(queue, ^{
        NSLog(@"9");
    });
}

// A: 1230789
// B: 1237890
// C: 3120798
// D: 2137890

答案是 A
分析: 串行队列相当于把异步变成同步按顺序执行,保证FIFO。异步函数串行队列:开启一条新线程 任务一个接着一个

- (void)wbinterDemo{
    // 并发队列
    dispatch_queue_t queue = dispatch_queue_create("com.demo.test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"1");
    });
    dispatch_async(queue, ^{
        NSLog(@"2");
    });
    dispatch_sync(queue, ^{ NSLog(@"3"); });
    NSLog(@"0");
    dispatch_async(queue, ^{
        NSLog(@"7");
    });
    dispatch_async(queue, ^{
        NSLog(@"8");
    });
    dispatch_async(queue, ^{
        NSLog(@"9");
    });
}

// A: 1230789
// B: 1237890
// C: 3120798
// D: 2137890

答案是 A C
分析: 同步函数代码块中NSLog(@"3");一定会堵塞NSLog(@"0");以下的代码,所以3一定在0之前,0肯定在7 8 9之前。并发队列1 2 3之间没有先后顺序,7 8 9之间也没有先后顺序,最终满足条件的是A C
注意: 同步函数只堵塞下面的代码,所以1 2 3没有先后顺序

主队列分析

队列一共有四种串行队列并发队列主队列全局并发队列

主队列
  • 专⻔用来在主线程上调度任务的串行队列
  • 不会开启线程
  • 如果当前主线程正在有任务执行,那么无论主队列中当前被添加了什么任务,都不会被调度dispatch_get_main_queue();
全局并发队列
  • 为了方便程序员的使用,苹果提供了全局队列 dispatch_get_global_queue(0, 0)
  • 全局队列是一个并发队列
  • 在使用多线程开发时,如果对队列没有特殊需求,在执行异步任务时,可以直接使用全局队列

串行队列: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);

主队列会在main函数之前创建

image.png
主队列分析

方式一

  • 通过bt打印分析
image.png
dispatch_get_main_queue(void)
{
    return DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q);
}

// 找到DISPATCH_GLOBAL_OBJECT宏定义
#define DISPATCH_GLOBAL_OBJECT(type, object) ((type)&(object))
  • 全局搜索_dispatch_main_q
// 6618342 Contact the team that owns the Instrument DTrace probe before
//         renaming this symbol
struct dispatch_queue_static_s _dispatch_main_q = {
    DISPATCH_GLOBAL_OBJECT_HEADER(queue_main),
#if !DISPATCH_USE_RESOLVERS
    .do_targetq = _dispatch_get_default_queue(true),
#endif
    .dq_state = DISPATCH_QUEUE_STATE_INIT_VALUE(1) |
            DISPATCH_QUEUE_ROLE_BASE_ANON,
    .dq_label = "com.apple.main-thread",
    .dq_atomic_flags = DQF_THREAD_BOUND | DQF_WIDTH(1),
    .dq_serialnum = 1,
};

方式二

  • 通过bt打印主队列找到名称

    截屏2021-09-11 下午4.19.00.png
  • 全局搜索com.apple.main-thread

    image.png

.dq_atomic_flags = DQF_WIDTH(1),.dq_serialnum = 1可知是串行队列。下面我们分析为什么.dq_atomic_flags = DQF_WIDTH(1)就是串行队列?

串行和并发的底层源码

  • 串行队列并行队列都是通过dispatch_queue_create创建的,下面我们在源码中搜索
image.png
  • 进入_dispatch_lane_create_with_target,看该方法的返回值
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)
    //

    // 省略代码
    ......

    //
    // Step 2: Initialize the queue
    //

    // 因为dq是返回值,这里主要查看dq是如何创建的
    dispatch_lane_t dq = _dispatch_object_alloc(vtable,
            sizeof(struct dispatch_lane_s));
    // 如果是并发队列返回DISPATCH_QUEUE_WIDTH_MAX,否则返回1
    _dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?
            DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
            (dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0));
      // 省略代码
    ......
    return _dispatch_trace_queue_create(dq)._dq;
}
  • 进入_dispatch_queue_init查看传值dqai_concurrent ?DISPATCH_QUEUE_WIDTH_MAX : 1
static inline dispatch_queue_class_t
_dispatch_queue_init(dispatch_queue_class_t dqu, dispatch_queue_flags_t dqf,
        uint16_t width, uint64_t initial_state_bits)
{
    uint64_t dq_state = DISPATCH_QUEUE_STATE_INIT_VALUE(width);
    dispatch_queue_t dq = dqu._dq;

    dispatch_assert((initial_state_bits & ~(DISPATCH_QUEUE_ROLE_MASK |
            DISPATCH_QUEUE_INACTIVE)) == 0);

    if (initial_state_bits & DISPATCH_QUEUE_INACTIVE) {
        dq->do_ref_cnt += 2; // rdar://8181908 see _dispatch_lane_resume
        if (dx_metatype(dq) == _DISPATCH_SOURCE_TYPE) {
            dq->do_ref_cnt++; // released when DSF_DELETED is set
        }
    }

    dq_state |= initial_state_bits;
    dq->do_next = DISPATCH_OBJECT_LISTLESS;
    // 在这里找到
    dqf |= DQF_WIDTH(width);
    os_atomic_store2o(dq, dq_atomic_flags, dqf, relaxed);
    dq->dq_state = dq_state;
    dq->dq_serialnum =
            os_atomic_inc_orig(&_dispatch_queue_serial_numbers, relaxed);
    return dqu;
}

得出结论
DQF_WIDTH = 1就为串行队列,跟dq_serialnum=1没有关系

dq_serialnum中的_dispatch_queue_serial_numbers只是一个标识,下面进行分析

  • 全局搜索_dispatch_queue_serial_numbers
unsigned long volatile _dispatch_queue_serial_numbers =
        DISPATCH_QUEUE_SERIAL_NUMBER_INIT;

// 全局搜索DISPATCH_QUEUE_SERIAL_NUMBER_INIT
// skip zero
// 1 - main_q   -> NUMBER为1就是主队列
// 2 - mgr_q
// 3 - mgr_root_q
// 4,5,6,7,8,9,10,11,12,13,14,15 - global queues
// 17 - workloop_fallback_q
// we use 'xadd' on Intel, so the initial value == next assigned
#define DISPATCH_QUEUE_SERIAL_NUMBER_INIT 17
  • 全局搜索查看os_atomic_inc_orig方法
#define os_atomic_inc_orig(p, m) \
        os_atomic_add_orig((p), 1, m)

#define os_atomic_add_orig(p, v, m) \
        _os_atomic_c11_op_orig((p), (v), m, add, +)

#define _os_atomic_c11_op_orig(p, v, m, o, op) \
        atomic_fetch_##o##_explicit(_os_atomic_c11_atomic(p), v, \
        memory_order_##m)
  • 最终演变为atomic_fetch_add_explicit函数

_dispatch_lane_create_with_target中有一个面向对象封装的方法
_dispatch_queue_attr_to_info,下面进行查看

  • 串行队列传NULL的原因,就是当dqaiNULL时,直接返回dqai
dispatch_queue_attr_info_t
_dispatch_queue_attr_to_info(dispatch_queue_attr_t dqa)
{
    dispatch_queue_attr_info_t dqai = { };

    if (!dqa) return dqai;

#if DISPATCH_VARIANT_STATIC
    if (dqa == &_dispatch_queue_attr_concurrent) {
        dqai.dqai_concurrent = true;
        return dqai;
    }
#endif

    if (dqa < _dispatch_queue_attrs ||
            dqa >= &_dispatch_queue_attrs[DISPATCH_QUEUE_ATTR_COUNT]) {
#ifndef __APPLE__
        if (memcmp(dqa, &_dispatch_queue_attrs[0],
                sizeof(struct dispatch_queue_attr_s)) == 0) {
            dqa = (dispatch_queue_attr_t)&_dispatch_queue_attrs[0];
        } else
#endif // __APPLE__
        DISPATCH_CLIENT_CRASH(dqa->do_vtable, "Invalid queue attribute");
    }

    size_t idx = (size_t)(dqa - _dispatch_queue_attrs);
    // 位运算处理
    dqai.dqai_inactive = (idx % DISPATCH_QUEUE_ATTR_INACTIVE_COUNT);
    idx /= DISPATCH_QUEUE_ATTR_INACTIVE_COUNT;

    dqai.dqai_concurrent = !(idx % DISPATCH_QUEUE_ATTR_CONCURRENCY_COUNT);
    idx /= DISPATCH_QUEUE_ATTR_CONCURRENCY_COUNT;

    dqai.dqai_relpri = -(int)(idx % DISPATCH_QUEUE_ATTR_PRIO_COUNT);
    idx /= DISPATCH_QUEUE_ATTR_PRIO_COUNT;

    dqai.dqai_qos = idx % DISPATCH_QUEUE_ATTR_QOS_COUNT;
    idx /= DISPATCH_QUEUE_ATTR_QOS_COUNT;

    dqai.dqai_autorelease_frequency =
            idx % DISPATCH_QUEUE_ATTR_AUTORELEASE_FREQUENCY_COUNT;
    idx /= DISPATCH_QUEUE_ATTR_AUTORELEASE_FREQUENCY_COUNT;

    dqai.dqai_overcommit = idx % DISPATCH_QUEUE_ATTR_OVERCOMMIT_COUNT;
    idx /= DISPATCH_QUEUE_ATTR_OVERCOMMIT_COUNT;

    return dqai;
}

GCD底层源码继承链

下面来分析全局并发队列
image.png
  • 全局搜索com.apple.root.default-qos

    image.png
  • 由于队列创建返回的都是dispatch_queue_t类型,就从这里入手开始探索

DISPATCH_DECL(dispatch_queue);

#define DISPATCH_DECL(name) OS_OBJECT_DECL_SUBCLASS(name, dispatch_object)
  • 源码中搜索OS_OBJECT_DECL_SUBCLASS
#define OS_OBJECT_DECL_SUBCLASS(name, super) \
        OS_OBJECT_DECL_IMPL(name, NSObject, <OS_OBJECT_CLASS(super)>)

#define OS_OBJECT_DECL_IMPL(name, adhere, ...) \
        OS_OBJECT_DECL_PROTOCOL(name, __VA_ARGS__) \
        typedef adhere<OS_OBJECT_CLASS(name)> \
                * OS_OBJC_INDEPENDENT_CLASS name##_t

#define OS_OBJECT_DECL_PROTOCOL(name, ...) \
        @protocol OS_OBJECT_CLASS(name) __VA_ARGS__ \
        @end

// 拼接一个_vtable
#define OS_OBJECT_CLASS_SYMBOL(name) _##name##_vtable
  • DISPATCH_DECL在源码中对应
#define DISPATCH_DECL(name) \
        typedef struct name##_s : public dispatch_object_s {} *name##_t

// 都是dispatch_object_t类型
#ifndef __DISPATCH_BUILDING_DISPATCH__
typedef union {
    struct _os_object_s *_os_obj;
    struct dispatch_object_s *_do;
    struct dispatch_queue_s *_dq;
    struct dispatch_queue_attr_s *_dqa;
    struct dispatch_group_s *_dg;
    struct dispatch_source_s *_ds;
    struct dispatch_channel_s *_dch;
    struct dispatch_mach_s *_dm;
    struct dispatch_mach_msg_s *_dmsg;
    struct dispatch_semaphore_s *_dsema;
    struct dispatch_data_s *_ddata;
    struct dispatch_io_s *_dchannel;
} dispatch_object_t DISPATCH_TRANSPARENT_UNION;
#endif // !__DISPATCH_BUILDING_DISPATCH__

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{ isa superclass } ->objc_object

最终的继承链关系dispatch_queue_t->dispatch_queue_s->dispatch_object_s->_os_object_s->dispatch_object_t

MT和KS面试题

面试题一

// 声明属性num
@interface ViewController ()
@property (atomic, assign) int num;
@end

// 美团面试题
- (void)MTDemo{
    while (self.num < 5) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            self.num++;
        });
    }
    NSLog(@"end : %d",self.num); 
}

结果:最终num的值大于等于5
分析: 因为是异步函数,当num<5的时候,至少会开辟5个以上的线程,最终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); 
}

结果:最终num的值小于等于10000
分析: 因为是异步函数而for循环只执行1000次。当for循环执行结束的时候,有可能一些异步函数还没有执行完成,这个时候num值必然小于等于10000

GCD的任务执行堆栈(同步)

dispatch_syncblock()在什么时候执行? 全局搜索dispatch_sync(dis源码如下

DISPATCH_NOINLINE
void
dispatch_sync(dispatch_queue_t dq, dispatch_block_t work)
{
    uintptr_t dc_flags = DC_FLAG_BLOCK;
    if (unlikely(_dispatch_block_has_private_data(work))) {
        return _dispatch_sync_block_with_privdata(dq, work, dc_flags);
    }
    _dispatch_sync_f(dq, work, _dispatch_Block_invoke(work), dc_flags);
}
#endif // __BLOCKS__
  • 查看传入的参数work去了哪里?这里查看_dispatch_Block_invoke方法
#define _dispatch_Block_invoke(bb) \
        ((dispatch_function_t)((struct Block_layout *)bb)->invoke)
  • 查看_dispatch_sync_f
DISPATCH_NOINLINE
static void
_dispatch_sync_f(dispatch_queue_t dq, void *ctxt, dispatch_function_t func,
        uintptr_t dc_flags)
{
    _dispatch_sync_f_inline(dq, ctxt, func, dc_flags);
}
  • 查看_dispatch_sync_f_inline
DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_sync_f_inline(dispatch_queue_t dq, void *ctxt,
        dispatch_function_t func, uintptr_t dc_flags)
{
    if (likely(dq->dq_width == 1)) {
        return _dispatch_barrier_sync_f(dq, ctxt, func, dc_flags);
    }

    if (unlikely(dx_metatype(dq) != _DISPATCH_LANE_TYPE)) {
        DISPATCH_CLIENT_CRASH(0, "Queue type doesn't support dispatch_sync");
    }

    dispatch_lane_t dl = upcast(dq)._dl;
    // Global concurrent queues and queues bound to non-dispatch threads
    // always fall into the slow case, see DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE
    if (unlikely(!_dispatch_queue_try_reserve_sync_width(dl))) {
        return _dispatch_sync_f_slow(dl, ctxt, func, 0, dl, dc_flags);
    }

    if (unlikely(dq->do_targetq->do_targetq)) {
        return _dispatch_sync_recurse(dl, ctxt, func, dc_flags);
    }
    _dispatch_introspection_sync_begin(dl);
    _dispatch_sync_invoke_and_complete(dl, ctxt, func DISPATCH_TRACE_ARG(
            _dispatch_trace_item_sync_push_pop(dq, ctxt, func, dc_flags)));
}
  • 加一个符号断点_dispatch_sync_f_slow发现进入了
    image.png
DISPATCH_NOINLINE
static void
_dispatch_sync_f_slow(dispatch_queue_class_t top_dqu, void *ctxt,
        dispatch_function_t func, uintptr_t top_dc_flags,
        dispatch_queue_class_t dqu, uintptr_t dc_flags)
{
    dispatch_queue_t top_dq = top_dqu._dq;
    dispatch_queue_t dq = dqu._dq;
    if (unlikely(!dq->do_targetq)) {
        return _dispatch_sync_function_invoke(dq, ctxt, func);
    }

    pthread_priority_t pp = _dispatch_get_priority();
    struct dispatch_sync_context_s dsc = {
        .dc_flags    = DC_FLAG_SYNC_WAITER | dc_flags,
        .dc_func     = _dispatch_async_and_wait_invoke,
        .dc_ctxt     = &dsc,
        .dc_other    = top_dq,
        .dc_priority = pp | _PTHREAD_PRIORITY_ENFORCE_FLAG,
        .dc_voucher  = _voucher_get(),
        .dsc_func    = func,
        .dsc_ctxt    = ctxt,
        .dsc_waiter  = _dispatch_tid_self(),
    };

    _dispatch_trace_item_push(top_dq, &dsc);
    __DISPATCH_WAIT_FOR_QUEUE__(&dsc, dq);

    if (dsc.dsc_func == NULL) {
        // dsc_func being cleared means that the block ran on another thread ie.
        // case (2) as listed in _dispatch_async_and_wait_f_slow.
        dispatch_queue_t stop_dq = dsc.dc_other;
        return _dispatch_sync_complete_recurse(top_dq, stop_dq, top_dc_flags);
    }

    _dispatch_introspection_sync_begin(top_dq);
    _dispatch_trace_item_pop(top_dq, &dsc);
    _dispatch_sync_invoke_and_complete_recurse(top_dq, ctxt, func,top_dc_flags
            DISPATCH_TRACE_ARG(&dsc));
}
  • 继续添加符号断点发现执行了_dispatch_sync_function_invoke方法
DISPATCH_NOINLINE
static void
_dispatch_sync_function_invoke(dispatch_queue_class_t dq, void *ctxt,
        dispatch_function_t func)
{
    _dispatch_sync_function_invoke_inline(dq, ctxt, func);
}
  • 查看_dispatch_sync_function_invoke_inline方法
DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_sync_function_invoke_inline(dispatch_queue_class_t dq, void *ctxt,
        dispatch_function_t func)
{
    dispatch_thread_frame_s dtf;
    _dispatch_thread_frame_push(&dtf, dq);
    _dispatch_client_callout(ctxt, func);
    _dispatch_perfmon_workitem_inc();
    _dispatch_thread_frame_pop(&dtf);
}
  • 查看_dispatch_client_callout方法
#undef _dispatch_client_callout
void
_dispatch_client_callout(void *ctxt, dispatch_function_t f)
{
    @try {
        return f(ctxt);
    }
    @catch (...) {
        objc_terminate();
    }
}
  • 断点bt验证探索流程
    image.png

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

dispatch_asyncblock()在什么时候执行?全局搜索dispatch_async(dis源码如下

#ifdef __BLOCKS__
void
dispatch_async(dispatch_queue_t dq, dispatch_block_t work)
{
    dispatch_continuation_t dc = _dispatch_continuation_alloc();
    uintptr_t dc_flags = DC_FLAG_CONSUME;
    dispatch_qos_t qos;

    qos = _dispatch_continuation_init(dc, dq, work, 0, dc_flags);
    _dispatch_continuation_async(dq, dc, qos, dc->dc_flags);
}
#endif
  • 查看_dispatch_continuation_init方法
DISPATCH_ALWAYS_INLINE
static inline dispatch_qos_t
_dispatch_continuation_init(dispatch_continuation_t dc,
        dispatch_queue_class_t dqu, dispatch_block_t work,
        dispatch_block_flags_t flags, uintptr_t dc_flags)
{
    void *ctxt = _dispatch_Block_copy(work);

    dc_flags |= DC_FLAG_BLOCK | DC_FLAG_ALLOCATED;
    if (unlikely(_dispatch_block_has_private_data(work))) {
        dc->dc_flags = dc_flags;
        dc->dc_ctxt = ctxt;
        // will initialize all fields but requires dc_flags & dc_ctxt to be set
        return _dispatch_continuation_init_slow(dc, dqu, flags);
    }

    dispatch_function_t func = _dispatch_Block_invoke(work);
    if (dc_flags & DC_FLAG_CONSUME) {
        func = _dispatch_call_block_and_release;
    }
    return _dispatch_continuation_init_f(dc, dqu, ctxt, func, flags, dc_flags);
}
  • 查看_dispatch_continuation_init_f方法
  • 查看_dispatch_continuation_priority_set优先级异步处理
DISPATCH_ALWAYS_INLINE
static inline dispatch_qos_t
_dispatch_continuation_priority_set(dispatch_continuation_t dc,
        dispatch_queue_class_t dqu,
        pthread_priority_t pp, dispatch_block_flags_t flags)
{
    dispatch_qos_t qos = DISPATCH_QOS_UNSPECIFIED;
#if HAVE_PTHREAD_WORKQUEUE_QOS
    dispatch_queue_t dq = dqu._dq;

    if (likely(pp)) {
        bool enforce = (flags & DISPATCH_BLOCK_ENFORCE_QOS_CLASS);
        bool is_floor = (dq->dq_priority & DISPATCH_PRIORITY_FLAG_FLOOR);
        bool dq_has_qos = (dq->dq_priority & DISPATCH_PRIORITY_REQUESTED_MASK);
        if (enforce) {
            pp |= _PTHREAD_PRIORITY_ENFORCE_FLAG;
            qos = _dispatch_qos_from_pp_unsafe(pp);
        } else if (!is_floor && dq_has_qos) {
            pp = 0;
        } else {
            qos = _dispatch_qos_from_pp_unsafe(pp);
        }
    }
    dc->dc_priority = pp;
#else
    (void)dc; (void)dqu; (void)pp; (void)flags;
#endif
    return qos;
}

查看_dispatch_continuation_async方法

DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_continuation_async(dispatch_queue_class_t dqu,
        dispatch_continuation_t dc, dispatch_qos_t qos, uintptr_t dc_flags)
{
#if DISPATCH_INTROSPECTION
    if (!(dc_flags & DC_FLAG_NO_INTROSPECTION)) {
        _dispatch_trace_item_push(dqu, dc);
    }
#else
    (void)dc_flags;
#endif
    return dx_push(dqu._dq, dc, qos);
}
  • 查看dx_push
#define dx_push(x, y, z) dx_vtable(x)->dq_push(x, y, z)
  • 查看dq_push queue_global队列

    image.png
  • 查看_dispatch_root_queue_push方法

  • 查看_dispatch_root_queue_push_inline,因为_dispatch_root_queue_push最终会执行到_dispatch_root_queue_push

DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_root_queue_push_inline(dispatch_queue_global_t dq,
        dispatch_object_t _head, dispatch_object_t _tail, int n)
{
    struct dispatch_object_s *hd = _head._do, *tl = _tail._do;
    if (unlikely(os_mpsc_push_list(os_mpsc(dq, dq_items), hd, tl, do_next))) {
        return _dispatch_root_queue_poke(dq, n, 0);
    }
}
  • 查看_dispatch_root_queue_poke方法
  • 查看_dispatch_root_queue_poke_slow方法
DISPATCH_NOINLINE
static void
_dispatch_root_queue_poke_slow(dispatch_queue_global_t dq, int n, int floor)
{
    int remaining = n;
#if !defined(_WIN32)
    int r = ENOSYS;
#endif

    _dispatch_root_queues_init();
    _dispatch_debug_root_queue(dq, __func__);
    _dispatch_trace_runtime_event(worker_request, dq, (uint64_t)n);
...... //省略代码 
  • 查看_dispatch_root_queues_init方法

    image.png
  • 查看_dispatch_root_queues_init_once方法,打印堆栈查看到调用的_dispatch_worker_thread2

    image.png
  • 查看_dispatch_worker_thread2方法

#if !DISPATCH_USE_INTERNAL_WORKQUEUE
static void
_dispatch_worker_thread2(pthread_priority_t pp)
{
    bool overcommit = pp & _PTHREAD_PRIORITY_OVERCOMMIT_FLAG;
    dispatch_queue_global_t dq;

    pp &= _PTHREAD_PRIORITY_OVERCOMMIT_FLAG | ~_PTHREAD_PRIORITY_FLAGS_MASK;
    _dispatch_thread_setspecific(dispatch_priority_key, (void *)(uintptr_t)pp);
    dq = _dispatch_get_root_queue(_dispatch_qos_from_pp(pp), overcommit);

    _dispatch_introspection_thread_add();
    _dispatch_trace_runtime_event(worker_unpark, dq, 0);

    int pending = os_atomic_dec2o(dq, dgq_pending, relaxed);
    dispatch_assert(pending >= 0);
    _dispatch_root_queue_drain(dq, dq->dq_priority,
            DISPATCH_INVOKE_WORKER_DRAIN | DISPATCH_INVOKE_REDIRECTING_DRAIN);
    _dispatch_voucher_debug("root queue clear", NULL);
    _dispatch_reset_voucher(NULL, DISPATCH_THREAD_PARK);
    _dispatch_trace_runtime_event(worker_park, NULL, 0);
}
#endif // !DISPATCH_USE_INTERNAL_WORKQUEUE
  • 查看_dispatch_root_queue_drain方法
  • 查看_dispatch_continuation_pop_inline方法
DISPATCH_ALWAYS_INLINE_NDEBUG
static inline void
_dispatch_continuation_pop_inline(dispatch_object_t dou,
        dispatch_invoke_context_t dic, dispatch_invoke_flags_t flags,
        dispatch_queue_class_t dqu)
{
    dispatch_pthread_root_queue_observer_hooks_t observer_hooks =
            _dispatch_get_pthread_root_queue_observer_hooks();
    if (observer_hooks) observer_hooks->queue_will_execute(dqu._dq);
    flags &= _DISPATCH_INVOKE_PROPAGATE_MASK;
    if (_dispatch_object_has_vtable(dou)) {
        dx_invoke(dou._dq, dic, flags);
    } else {
        _dispatch_continuation_invoke_inline(dou, flags, dqu);
    }
    if (observer_hooks) observer_hooks->queue_did_execute(dqu._dq);
}
  • 查看_dispatch_continuation_invoke_inline方法
  • 查看_dispatch_client_callout方法
// 实质上是一个调用执行
DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_client_callout(void *ctxt, dispatch_function_t f)
{
    return f(ctxt);
}

相关文章

网友评论

      本文标题:GCD分析(上)

      本文链接:https://www.haomeiwen.com/subject/vboowltx.html