iOS 多线程知识体系构建(八):GCD 源码:队列创建(自定义、根队列、主队列)

在 GCD 中使用最多的三种队列:主队列(dispatch_get_main_queue())、全局并发队列(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0))、自定义队列(dispatch_queue_create),那么我们就先由创建自定义队列开始学习。dispatch_queue_create(创建自定义队列)下面就沿着源码一路看队列的创建过程。// 创建一个并发队列dispatch_queue_t concurrent
摘要由CSDN通过智能技术生成

在 GCD 中使用最多的三种队列:主队列(dispatch_get_main_queue())、全局并发队列(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0))、自定义队列(dispatch_queue_create),那么我们就先由创建自定义队列开始学习。

dispatch_queue_create(创建自定义队列)

下面就沿着源码一路看队列的创建过程。

// 创建一个并发队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.concurrent", DISPATCH_QUEUE_CONCURRENT);
// 创建一个串行队列
dispatch_queue_t serialQueue = dispatch_queue_create("com.serial", DISPATCH_QUEUE_SERIAL);

DISPATCH_QUEUE_SERIAL

用于创建以 FIFO 顺序串行调用块的调度队列(串行队列)的属性,值是 NULL

#define DISPATCH_QUEUE_SERIAL NULL

DISPATCH_QUEUE_CONCURRENT

可用于创建调度队列(并发队列)的属性,该调度队列可同时调用块并支持通过调度屏障 API (dispatch_barrier_async)提交的屏障块。(常规 block 和 barrier 的 block 任务块)

#define DISPATCH_GLOBAL_OBJECT(type, object) ((OS_OBJECT_BRIDGE type)&(object))

#define DISPATCH_QUEUE_CONCURRENT \
        DISPATCH_GLOBAL_OBJECT(dispatch_queue_attr_t, _dispatch_queue_attr_concurrent)
API_AVAILABLE(macos(10.7), ios(4.3))
DISPATCH_EXPORT
struct dispatch_queue_attr_s _dispatch_queue_attr_concurrent; // 这里有一个 dispatch_queue_attr_s 结构体类型的全局变量。

DISPATCH_QUEUE_CONCURRENT 宏定义是把全局变量 _dispatch_queue_attr_concurrent 强制转化为了 dispatch_queue_attr_t 类型的变量。

dispatch_queue_create 函数的实现。label 参数是要附加到队列的自定义的字符串标签,attr 参数是预定义属性,DISPATCH_QUEUE_SERIALDISPATCH_QUEUE_CONCURRENT 或调用 dispatch_queue_attr_make_with_* 函数的自定义创建的 dispatch_queue_attr_t 结构体实例。

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_queue_create 函数内部调用了一个中间函数 _dispatch_lane_create_with_target,其中用了一个 DISPATCH_TARGET_QUEUE_DEFAULT 作为默认参数。

DISPATCH_TARGET_QUEUE_DEFAULT

DISPATCH_TARGET_QUEUE_DEFAULT 是传递给 dispatch_queue_create_with_targetdispatch_set_target_queuedispatch_source_create 函数的常量,以指示应使用(相关对象类型的)默认目标队列,它的实际值是 NULL

#define DISPATCH_TARGET_QUEUE_DEFAULT NULL

dispatch_lane_t

dispatch_lane_t 是指向 dispatch_lane_s 结构体的指针。

typedef struct dispatch_lane_s {
    DISPATCH_LANE_CLASS_HEADER(lane);
    /* 32bit hole on LP64 */
} DISPATCH_ATOMIC64_ALIGN *dispatch_lane_t;
DISPATCH_LANE_CLASS_HEADER
#define DISPATCH_LANE_CLASS_HEADER(x) \
    struct dispatch_queue_s _as_dq[0]; \
    DISPATCH_QUEUE_CLASS_HEADER(x, \
            struct dispatch_object_s *volatile dq_items_tail); \
    dispatch_unfair_lock_s dq_sidelock; \
    struct dispatch_object_s *volatile dq_items_head; \
    uint32_t dq_side_suspend_cnt

dispatch_lane_s 定义中的宏完全展开的话:

typedef struct dispatch_lane_s {
    // 此处两行则是 dispatch_lane_s 继承的父类 dispatch_queue_s 的头部内容
    struct dispatch_queue_s _as_dq[0];
    struct dispatch_object_s _as_do[0];
    struct _os_object_s _as_os_obj[0];

    const struct dispatch_lane_vtable_s *do_vtable; /* must be pointer-sized */
    int volatile do_ref_cnt;
    int volatile do_xref_cnt;

    struct dispatch_lane_s *volatile do_next;
    struct dispatch_queue_s *do_targetq;
    void *do_ctxt;
    void *do_finalizer

    struct dispatch_object_s *volatile dq_items_tail;

    union { 
        uint64_t volatile dq_state;
        struct {
            dispatch_lock dq_state_lock;
            uint32_t dq_state_bits;
        };
    };

    /* LP64 global queue cacheline boundary */
    unsigned long dq_serialnum;
    const char *dq_label;

    union { 
        uint32_t volatile dq_atomic_flags;
        struct {
            const uint16_t dq_width; // 队列的宽度(串行队列为 1,并发队列大于 1)
            const uint16_t __dq_opaque2;
        };
    };

    dispatch_priority_t dq_priority;
    union {
        struct dispatch_queue_specific_head_s *dq_specific_head;
        struct dispatch_source_refs_s *ds_refs;
        struct dispatch_timer_source_refs_s *ds_timer_refs;
        struct dispatch_mach_recv_refs_s *dm_recv_refs;
        struct dispatch_channel_callbacks_s const *dch_callbacks;
    };
    int volatile dq_sref_cnt;

    dispatch_unfair_lock_s dq_sidelock; // 锁
    struct dispatch_object_s *volatile dq_items_head; // 头
    uint32_t dq_side_suspend_cnt // 挂起次数

} DISPATCH_ATOMIC64_ALIGN *dispatch_lane_t;

这里有一个iOS交流圈有兴趣的可以了解一下:891 488 181 分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长!
 可看到 dispatch_lane_s 是继承自 dispatch_queue_s 的“子类”,且 _dispatch_lane_create_with_target 函数返回的正是 dispatch_lane_s 而不是 dispatch_queue_s 类型。

DISPATCH_QUEUE_WIDTH_MAX

#define DISPATCH_QUEUE_WIDTH_FULL            0x1000ull //(4096)为创建全局队列时候所使用的
#define DISPATCH_QUEUE_WIDTH_POOL (DISPATCH_QUEUE_WIDTH_FULL - 1) // 0xfffull(4095)
#define DISPATCH_QUEUE_WIDTH_MAX  (DISPATCH_QUEUE_WIDTH_FULL - 2) // 0xffeull // 队列宽度的最大值 (4094)

_dispatch_priority_make

优先级及相对量。

#define _dispatch_priority_make(qos, relpri) \
    (qos ? ((((qos) << DISPATCH_PRIORITY_QOS_SHIFT) & DISPATCH_PRIORITY_QOS_MASK) | \
    ((dispatch_priority_t)(relpri - 1) & DISPATCH_PRIORITY_RELPRI_MASK)) : 0)

_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_to_info 函数上篇我们讲解过,
    // 1\. 如果 dqa 是 DISPATCH_QUEUE_SERIAL(值是 NULL)作为入参传入的话,
    //    会直接返回一个空的 dispatch_queue_attr_info_t 结构体实例,(dispatch_queue_attr_info_t dqai = { };)。
    // 2\. 如果 dqa 是 DISPATCH_QUEUE_CONCURRENT(值是全局变量 _dispatch_queue_attr_concurrent)作为入参传入的话,
    //    会返回一个 dqai_concurrent 值是 true 的 dispatch_queue_attr_info_t 结构体实例,(dqai_concurrent 为 true 表示是并发队列)。
    // 3\. 第三种情况则是传入自定义的 dispatch_queue_attr_t 时,
    //    则会进行取模和取商运算为 dispatch_queue_attr_info_t 结构体实例的每个成员变量赋值后返回该 dispatch_queue_attr_info_t 结构体实例。

    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; //(dqai_qos 表示线程优先级)

    // 如果 HAVE_PTHREAD_WORKQUEUE_QOS 为假会进行一个 dqai_qos 的切换
#if !HAVE_PTHREAD_WORKQUEUE_QOS
    if (qos == DISPATCH_QOS_USER_INTERACTIVE) {
        // 如果是 "用户交互" 这个最高优先级,则切到 "用户启动" 这个第二优先级
        dqai.dqai_qos = qos = DISPATCH_QOS_USER_INITIATED;
    }
    if (qos == DISPATCH_QOS_MAINTENANCE) {
        // 如果是 "QOS_CLASS_MAINTENANCE" 这个最低优先级,则切到 "后台线程" 这个倒数第二优先级
        dqai.dqai_qos = qos = DISPATCH_QOS_BACKGROUND;
    }
#endif // !HAVE_PTHREAD_WORKQUEUE_QOS

    // 取出是否允许 "过量使用(超过物理上的核心数)"
    _dispatch_queue_attr_overcommit_t overcommit = dqai.dqai_overcommit;
    if (overcommit != _dispatch_queue_attr_overcommit_unspecified && tq) {
        // 如果 overcommit 不等于 "未指定 overcommit" 并且 tq 不为空
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值