KittenYang

YYDispatchQueuePool 源码阅读笔记

首先明确几个函数:

  • 输入一个 NSQualityOfService qos ,输出一个 YYDispatchContext
  • 输入当前的 context,输出一个队列 dispatch_queue_t
  • 输入 NSQualityOfService,输出 qos_class_t
  • 输入 NSQualityOfService,输出 dispatch_queue_priority_t
  • 输入原始信息 const char *name,uint32_t queueCount,NSQualityOfService qos),创建一个 YYDispatchContext

NSQualityOfService 有五个可选值:

NSQualityOfServiceUserInteractive  
NSQualityOfServiceUserInitiated  
NSQualityOfServiceUtility  
NSQualityOfServiceBackground  
NSQualityOfServiceDefault

实现步骤

步骤1:

+ (instancetype)defaultPoolForQOS:(NSQualityOfService)qos 中判断pos类型: 根据不同的 pos 类型创建一个单例。创建通过 - (instancetype)initWithContext:(YYDispatchContext *)context 方法。

步骤2:

- (instancetype)initWithContext:(YYDispatchContext *)context 需要一个结构体 YYDispatchContext

typedef struct{  
  const char *name;
  void **queues;
  uint32_t queueCount;
  int32_t counter;
}YYDispatchContext;

参数 context 通过 static YYDispatchContext *YYDispatchContextGetForQOS (NSQualityOfService qos) 方法创建

步骤3:

static YYDispatchContext *YYDispatchContextGetForQOS(NSQualityOfService qos) 中遍历 qos

疑问1:为什么这里还要 dispatch_once ?外层的函数已经能保证只执行一次了。

疑问2:为什么要创建一个临时数组 —— YYDispatchContext *context[5] = {0},switch 会且只会匹配到一个 case 。

context 实例通过 static YYDispatchContext *YYDispatchContextCreate(const char *name,uint32_t queueCount, NSQualityOfService qos) 创建。

步骤4:

static YYDispatchContext *YYDispatchContextCreate(const char *name,uint32_t queueCount, NSQualityOfService qos)

创建 context 最重要的是创建 queues,并且 queues 具有和 qos 匹配的优先级,对应关系为:

NSQualityOfServiceUserInteractive  —- DISPATCH_QUEUE_PRIORITY_HIGH  
NSQualityOfServiceUserInitiated    —- DISPATCH_QUEUE_PRIORITY_HIGH  
NSQualityOfServiceUtility        —-   DISPATCH_QUEUE_PRIORITY_LOW  
NSQualityOfServiceBackground     —-   DISPATCH_QUEUE_PRIORITY_BACKGROUND  
NSQualityOfServiceDefault        —-   DISPATCH_QUEUE_PRIORITY_DEFAULT  

首先创建队列无非是用 dispatch_queue_create , 所以核心函数就是 dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr); 需要指定一个标识符 labelattr, attr 可以是 DISPATCH_QUEUE_SERIAL 或者 DISPATCH_QUEUE_CONCURRENT

但是如何指定优先级就有区别呢?

a. 在8.0之前:

先直接创建一个串行队列 dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL); 再通过 dispatch_set_target_queue(dispatch_object_t object, dispatch_queue_t queue); 这个函数可以改变object的优先级与目标queue相同,第一个参数为要设置优先级的queue,第二个参数是参照 物,既将第一个queue的优先级和第二个queue的优先级设置一样而服务质量优先级的标识符 qos 的和队列优先级的对应关系上面已经提到:

NSQualityOfServiceUserInteractive  —- DISPATCH_QUEUE_PRIORITY_HIGH  
NSQualityOfServiceUserInitiated    —- DISPATCH_QUEUE_PRIORITY_HIGH  
NSQualityOfServiceUtility        —-   DISPATCH_QUEUE_PRIORITY_LOW  
NSQualityOfServiceBackground     —-   DISPATCH_QUEUE_PRIORITY_BACKGROUND  
NSQualityOfServiceDefault        —-   DISPATCH_QUEUE_PRIORITY_DEFAULT

b.在8.0以后

就比较简单了,可以通过这个方法: dispatch_queue_attr_make_with_qos_class(dispatch_queue_attr_t attr, dispatch_qos_class_t qos_class, int relative_priority); 设置队列优先级,qos 和 qos_class 的对应关系为:

    NSQualityOfServiceUserInteractive: return QOS_CLASS_USER_INTERACTIVE;
    NSQualityOfServiceUserInitiated: return QOS_CLASS_USER_INITIATED;
    NSQualityOfServiceUtility: return QOS_CLASS_USER_INITIATED;
    NSQualityOfServiceBackground: return QOS_CLASS_BACKGROUND;
    NSQualityOfServiceDefault: return QOS_CLASS_DEFAULT;
    default: return QOS_CLASS_UNSPECIFIED;

回到 步骤3,继续。

context 创建完成。

回到 步骤1YYDispatchQueuePool 实例创建完成.

这就是+ (instancetype)defaultPoolForQOS:(NSQualityOfService)qos 经历的完整过程。

当我们需要从队列池中取队列是,调用 -(dispatch_queue_t)queue;

规则是: 根据当前线程池的上下文信息也就是 context

static dispatch_queue_t YYDispatchContextGetQueue(YYDispatchContext *context) {  
  int32_t counter = OSAtomicIncrement32(&context->counter); // 为了更安全地递增一个全局计数器,我们使用 OSAtomicIncrement32 来原子操作级别地增加 counter 数
  if (counter < 0) counter = -counter;
  void *queue = context->queues[counter % context->queueCount];
  return (__bridge dispatch_queue_t)(queue);
}
KittenYang

写写代码,做做设计,看看产品。