首先明确几个函数:
- 输入一个
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);
需要指定一个标识符 label
和 attr
,
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 创建完成。
回到 步骤1, YYDispatchQueuePool
实例创建完成.
这就是+ (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);
}