美文网首页
23期_iOS_GCD的队列源码研读

23期_iOS_GCD的队列源码研读

作者: 萧修 | 来源:发表于2023-08-24 01:00 被阅读0次

源码研读:
[源码地址]https://opensource.apple.com/releases/)

主队列

我们通过断点nslog,并在控制台bt,可知gcd引自库
libdispatch.dylib

 dispatch_async(dispatch_get_main_queue(), ^{
        
    NSLog(@"GCD函数分析");
        
});

以下是堆栈的打印信息。

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x000000010014ddd4 005-GCD-源发研读`__29-[ViewController viewDidLoad]_block_invoke(.block_descriptor=0x00000001001500a0) at ViewController.m:22:9
    frame #1: 0x000000010071c528 libdispatch.dylib`_dispatch_call_block_and_release + 24
    frame #2: 0x000000010071dd50 libdispatch.dylib`_dispatch_client_callout + 16
    frame #3: 0x000000010072e808 libdispatch.dylib`_dispatch_main_queue_drain + 1316
    frame #4: 0x000000010072e2d4 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 40
    frame #5: 0x000000018039a784 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
    frame #6: 0x0000000180394de4 CoreFoundation`__CFRunLoopRun + 1912
    frame #7: 0x0000000180394254 CoreFoundation`CFRunLoopRunSpecific + 584
    frame #8: 0x0000000188eb7c9c GraphicsServices`GSEventRunModal + 160
    frame #9: 0x000000010761eff0 UIKitCore`-[UIApplication _run] + 868
    frame #10: 0x0000000107622f3c UIKitCore`UIApplicationMain + 124
    frame #11: 0x000000010014e02c 005-GCD-源发研读`main(argc=1, argv=0x000000016fcb1b38) at main.m:17:12
    frame #12: 0x00000001002dd514 dyld_sim`start_sim + 20
    frame #13: 0x00000001004e5f28 dyld`start + 2236
(lldb) 

dispatch_get_main_queue是通过DISPATCH_GLOBAL_OBJECT返回

DISPATCH_INLINE DISPATCH_ALWAYS_INLINE DISPATCH_CONST DISPATCH_NOTHROW
dispatch_queue_main_t
dispatch_get_main_queue(void)
{
    return DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q);
}

//查看此宏定义
#define DISPATCH_GLOBAL_OBJECT(type, object) ((type)&(object))
  • _dispatch_main_q
    查看第二个参数,下面列了此参数的结构,通过上面的打印com.apple.main-thread,也可从源码中进行搜索
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,
};
  • 主队列初始化在libdispatchinit()中
  • 获取默认队列,将主队列和当前队列和主线程绑定
DISPATCH_EXPORT DISPATCH_NOTHROW
void
libdispatch_init(void)
{

#if DISPATCH_USE_RESOLVERS // rdar://problem/8541707
    _dispatch_main_q.do_targetq = _dispatch_get_default_queue(true);
#endif

    _dispatch_queue_set_current(&_dispatch_main_q);
    _dispatch_queue_set_bound_thread(&_dispatch_main_q);
}

串行队列和并发队列

通过搜索dispatch_queue_create定位到queue.c文件
返回了_dispatch_lane_create_with_target

dispatch_queue_t
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
{
    return _dispatch_lane_create_with_target(label, attr,
            DISPATCH_TARGET_QUEUE_DEFAULT, true);
}

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);
    //根据队列类型创建dqai、dqa传入的属性串行还是并行
    
    //申请开辟内存
    dispatch_lane_t dq = _dispatch_object_alloc(vtable,
            sizeof(struct dispatch_lane_s));
            
    //初始化队列,判断是否并发,是的话传DISPATCH_QUEUE_WIDTH_MAX,否则传1。即串行队列传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));
}


  • _dispatch_queue_attr_to_infod
    qai,在这里进行了dqai的初始化,并判断队列类型

queue的info信息判断,根据传入的队列是串行还是并发

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
  • _dispatch_queue_init
    队列初始化函数

  • dq_width
    width此值为前面传过来的值,赋值qf |= DQF_WIDTH(width),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;
}
  • vtable

接下来分析vtable,构造末模板,根据dqai中dqai_concurrent,区分队列类型,

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)
{
const void *vtable;
    dispatch_queue_flags_t dqf = legacy ? DQF_MUTABLE : 0;
    if (dqai.dqai_concurrent) {
        vtable = DISPATCH_VTABLE(queue_concurrent);
    } else {
        vtable = DISPATCH_VTABLE(queue_serial);
    }
}

// DISPATCH_VTABLE定义
#define DISPATCH_VTABLE(name) DISPATCH_OBJC_CLASS(name)

// vtable symbols - 模板
#define DISPATCH_OBJC_CLASS(name) (&DISPATCH_CLASS_SYMBOL(name))

// 拼接形成类
#define DISPATCH_CLASS_SYMBOL(name) OS_dispatch_##name##_class

并发队列:
传queue_concurrent参数,最终拼接后,队列类型对应的类为:OS_dispatch_queue_concurrent
串行队列:
传queue_serial参数,最终拼接后,队列类型对应的类为:OS_dispatch_queue_serial
所以vtable对应的就是队列的类型。通过拼接完成类的定义

全局队列

服务质量

 *  - QOS_CLASS_USER_INTERACTIVE
 *  - QOS_CLASS_USER_INITIATED
 *  - QOS_CLASS_DEFAULT
 *  - QOS_CLASS_UTILITY
 *  - QOS_CLASS_BACKGROUND

优先级

 - DISPATCH_QUEUE_PRIORITY_HIGH:         QOS_CLASS_USER_INITIATED
 *  - DISPATCH_QUEUE_PRIORITY_DEFAULT:      QOS_CLASS_DEFAULT
 *  - DISPATCH_QUEUE_PRIORITY_LOW:          QOS_CLASS_UTILITY
 *  - DISPATCH_QUEUE_PRIORITY_BACKGROUND:   QOS_CLASS_BACKGROUND

API_AVAILABLE(macos(10.6), ios(4.0))
DISPATCH_EXPORT DISPATCH_CONST DISPATCH_WARN_RESULT DISPATCH_NOTHROW
dispatch_queue_global_t
dispatch_get_global_queue(intptr_t identifier, uintptr_t flags);

系统维护一个全局队列集合,根据不同服务质量和优先级提供不同并发队列

相关文章

网友评论

      本文标题:23期_iOS_GCD的队列源码研读

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