多线程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

 

 

原文地址:https://www.cnblogs.com/coolcold/p/12203391.html