GCD系列是阅读官方文件和在实践中总结的一些常见的GCD用法,基本涉及全部的GCD内容形成的集合文章,文章重点在与精简和全面覆盖。
学习本集合你可以了解:
1. GCD是如何做到多线程调度的
2. 对比其他iOS的多线程方案,GCD的优势和劣势
3. 如何使用GCD相关的API我将在后续不断补充详细内容和实际案例, 欢迎关注,提问和讨论
03-dispatch_after/dispatch_time-延迟调度和操作
04-dispatch_barrier_sync/async-线程阻塞
dispatch_sync将block转换后检查队列宽度为1,调用dispatch_barrier_sync_f
void dispatch_sync(dispatch_queue_t dq, void (^work)(void))
{
struct Block_basic *bb = (void *)work;
dispatch_sync_f(dq, work, (dispatch_function_t)bb -> Block_invoke);
}
void dispatch_sync_f(dispatch_queue_t dq, void *ctxt, dispatch_function_t func){
typeof(dq->dq_running) prev_cnt;
dispatch_queue_t old_dq;
if (dq->dq_width == 1) { 主队列满足条件
return dispatch_barrier_sync_f(dq, ctxt, func);
}
…..
}
void dispatch_barrier_sync_f(dispatch_queue_t dq, void *ctxt, dispatch_function_t func) {
dispatch_queue_t old_dq = _dispatch_thread_getspecific(dispatch_queue_key);
// 1) ensure that this thread hasn't enqueued anything ahead of this call 检查队列是否在尾部
// 2) the queue is not suspended 队列是否暂停挂起
// 3) the queue is not weird 队列是否能被正常加锁
if (slowpath(dq->dq_items_tail) 成立
|| slowpath(DISPATCH_OBJECT_SUSPENDED(dq))
|| slowpath(!_dispatch_queue_trylock(dq))) {
return _dispatch_barrier_sync_f_slow(dq, ctxt, func);
}
}
满足条件就会使用mutex(互斥锁)后去当前进程资源锁,执行block代码块.
然后释放锁整个调用结束; 由于线程阻塞的时候, 队列并不在尾部,
不满足条件就会跳入到_dispatch_barrier_sync_f_slow
static void _dispatch_barrier_sync_f_slow(dispatch_queue_t dq, void *ctxt, dispatch_function_t func) {
……. 一堆……
//---------------重点是这里---------------
使用_dispatch_queue_push将我们的block压入main queue的FIFO队列中
_dispatch_queue_push(dq, (void *)&dbss);
dispatch_semaphore_wait(dbss2.dbss2_sema, DISPATCH_TIME_FOREVER);然后等待信号量,ready后被唤醒。
_dispatch_put_thread_semaphore(dbss2.dbss2_sema);然后dispatch_semaphore_wait返回_dispatch_semaphore_wait_slow(dsema, timeout)函数,持续轮训并等待,直到条件满足
}
…………
所以在此过程中,我们最初调用的dispatch_sync函数一直得不到返回,main queue被阻塞,而我们的block又需要等待main queue来执行它。