我刚刚在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
只需添加工作项(我避免使用单词“block”可能会混淆)到队列A,则将发送此工作项
到queueA的目标队列,那么GCD将保留一个线程
此工作项
我已经阅读了许多与此相关的主题,例如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
阻止了队列,有人说ojit_code阻止了当前线程,... :(那么为什么会导致死锁呢?
最佳答案
dispatch_sync
阻塞当前线程,直到分派的代码完成为止;如果从串行队列同步分派,则也有效地阻塞了队列。因此,如果您从串行队列同步调度到其自身,则会导致死锁。
但是需要明确的是,dispatch_sync
阻止了当前线程,而不是当前队列。处理并发队列时,不同的工作线程将用于随后分派的块,并且不会导致死锁。
您似乎正在对《并发编程指南》的Dispatch Queues章末尾的讨论做出回应,该章说:
不要从传递给函数调用的同一队列中执行的任务中调用dispatch_sync
函数。这样做将使队列陷入僵局。如果需要调度到当前队列,请使用dispatch_async
函数异步进行。
这并不完全正确。如果(a)您正在并发队列中执行此操作; (b)有可用的工作线程,这不会导致死锁。但这是一个不好的做法,尽管如此,仍应避免。