将Queue中的api归类为:
同步sync:disptach_sync_f
异步async;disptach_async_f
异步延时asyncDelayed: 暂且叫disptach_cannel
取消延时disptach_source_cancel。
先看看一张队列调用的关系图:
这张图表明了GCD中队列的并发关系,除了globalqueue之外,其他的queue,都会在globalQueue中调度,调度之后再按照queue自身的结构调度。
1. sync
GlobalQueue和Private Queue(前面称为用户队列). 正对sync都是直接执行,封装的block没有直接压队,这部分应该是根据开发者自行的需要可以修改的。
2. Async
先从GlobalQueue入手;既然是异步的操作,就会存在多任务和多线程的问题,多任务主要看GCD如何维护这些任务;
GCD之所以用到这些队列,可以简单的认为是一种内存共享的方式,也就是先将任务放入队列, 通过一些规则管理起来,然后再创建线程,从队列中取出这些任务,然后执行。
上图则是任务的结构;
任务创建之后,需要将任务插入到队列,其流程图如下:
进入到probe阶段_dispatch_queue_wakeup_globel中后,获取dq的上下文c_txt;然后调用dispatch_smaphore_signal(c_txt->dgq_thread_mediator)。将信号值加1(原子操作),如果信号值大于0,表示当前资源可用,可以进行继续往下进行;否则表示有正在sleep的线程在等待唤醒,那么直接唤醒sleep的线程处理即可。
当semaphore_signal之后返回0,表示有可用资源,那么更新线程池的size(原子操作减1)。接下来创建工作线程_dispatch_work_thread。
创建子线程之后,进入到_dispatch_worker_thread中,先设置线程中信号掩码。执行_dispatch_worker_thread2。该函数用于真正执行任务。_dispatch_worker_thread2会循环的通过_dispatch_queue_concurrent_drain_one从dq中取出任务item。然后交给_dispatch_continuation_pop来执行。
_dispatch_queue_concurrent_drain_one的流程如下图。当获取之后返回Head,交给_dispatch_continuation_pop,_dispatch_continuation_pop获取到dispatch_continuation_t的dc对象后,通过dc_func(dc_ctxt)执行任务。
_dispatch_worker_thread2执行完后,回到了_dispatch_worker_thread,这时候会进入_dispatch_semaphore_wait(qc->dgq_thread_mediator,1seconds)。及线程会等待1s,看是否有其他资源过来,若发现可用资源为0,那么返回;否则继续执行。
子线程的work完成之后,将线程池大小加1,如果发现dq的tail非空,表示还有任务没有处理,那么重新进入_dispatch_queue_wakeup_global(dq)中。然后返回。当存在多个任务到达时,可能出现之前semphore_signal时,发现可用信号值为负值,那么表示有线程等待唤醒,这其实是多个子线程在_dispatch_semaphore_wait时引起的。因此只需要唤醒它们就行。