我刚刚在objc.io Going Fully Asynchronous上看过这个,但找不到好的解释
dispatch_queue_t queueA; // assume we have this
dispatch_sync(queueA, ^(){ // (a)
dispatch_sync(queueA, ^(){ // (b)
foo();
});
});
一旦我们点击第二个dispatch_sync,我们就会陷入僵局:我们无法发送 在queueA上,因为有人(当前线程)已经在那上面了 排队,永远不会离开它。
只要我明白
dispatch_sync
只需添加工作项(我避免使用“块”一词
因为它可能会混淆)到队列A,然后将发送此工作项
到queueA的目标队列,然后GCD将保留一个线程
此工作项的 threadWorkItem 我已经阅读了许多与此相关的帖子,例如Deadlock with dispatch_sync,Why can't we use a dispatch_sync on the current queue?,Why is this dispatch_sync() call freezing?,但是找不到好的解释。有人说dispatch_sync
阻塞队列,有人说它会阻塞当前线程,...... :(
那为什么会造成僵局?
答案 0 :(得分:11)
dispatch_sync
阻塞当前线程,直到调度的代码完成,如果您从串行队列同步调度,那么您也有效地阻塞了队列。因此,如果您从串行队列同步调度到自身,则会导致死锁。
但要明确,dispatch_sync
会阻止当前线程,而不是当前队列。处理并发队列时,不同的工作线程将用于随后调度的块,并且不会产生死锁。
您似乎正在回应并发编程指南 Dispatch Queues章末尾的讨论,其中说:
不要从传递给函数调用的同一队列上执行的任务中调用
dispatch_sync
函数。这样做会使队列死锁。如果需要调度到当前队列,请使用dispatch_async
函数异步执行此操作。
这不完全正确。如果(a)您使用并发队列执行此操作; (b)有可用的工作线程,这不会导致死锁。但这是一种不好的做法,应该避免使用。
答案 1 :(得分:0)
使用此代码从任何线程到主线程进行调用,没有死锁风险。请记住,如果队列的层次结构很深,你仍然可以陷入僵局。
static inline void dispatch_synchronized (dispatch_queue_t queue,
dispatch_block_t block)
{
dispatch_queue_set_specific (queue, (__bridge const void *)(queue), (void *)1, NULL);
if (dispatch_get_specific ((__bridge const void *)(queue)))
block ();
else
dispatch_sync (queue, block);
}