多线程GCD源码分析(三)
1. 之前栈栏函数在使用AFNetwork会出现问题。原因是AFN有一个自己的队列 ”com.almofire.cn.session“, 所以在使用的时候并不知道AFN底层有一个队列,就会出现栈栏函数失效没有达到之前顺序执行的预期。
libdispatch源码:https://opensource.apple.com/tarballs/libdispatch/ github:https://github.com/apple
首先查看队列是如何产生的:dispatch_queue_create(创建队列)
dispatch_queue_create("com.cooci.cn", NULL);
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]) {
DISPATCH_CLIENT_CRASH(dqa->do_vtable, "Invalid queue attribute");
}
// 苹果的算法
size_t idx = (size_t)(dqa - _dispatch_queue_attrs);
// 位域
// 0000 000000000 00000000000 0000 000 1
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 = -(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;
}
串行和并行的区分
_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_WIDTH_MAX,如果是串行队列传1
类似于NSObject
并发队列口子大,串行队列只能1个
_dispatch_root_queues[] 是一个系统初始化的静态数组,装了很多queue --target queue,这个也解释了全局是因为并发队列是放在静态数组里面的。
自己创建的并发和全局并发的width不一样自己的是0xffe,全局的是0xfff
dispatch_get_global_queue是直接用_dispatch_get_root_queue方法 从 rootqueue里面去的
主队列的获取:
dispatch_get_main_queue
主队列静态数组:
// dispatch_queue_main_t 串行队列
// DISPATCH_DECL_SUBCLASS(dispatch_queue_main, dispatch_queue_serial
// 重写,所以是串行队列
同步异步函数:
dispatch_sync(dis
_dispatch_sync_f(dis
_dispatch_sync_f_inline
死锁原因:调度3去执行,但是程序还在等待3。要被调度线程id的和被锁的等待执行完成的线程id是同一个就会发生死锁crash。
异步并发:
直接往工作队列中添加线程,并发就是在这里创建线程
这段代码是判断线程池容积,如果要创建的线程数大于可以创建的线程数,就会崩溃
并发队列pthread_creat其实就是普通的创建并发队列,利用do-while一直创建线程,知道--remaining
异步执行线程的block
执行block内容:
单例:
dispatch_once_t 是long类型的
val就是我们传进来的once_token,单例的意思是如果来过一次,下次就不过来,直接return。
如果执行过mark_done(1)
标记为DLOCK_ONCE_DONE
信号量 :
// 相当于-1
dispatch_wait(sem, DISPATCH_TIME_FOREVER);
调度组:
dispatch_group_create创建
dispatch_group_enter进组相当于-1
出组相当于+1