我刚刚在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将保留一个线程
    此工作项
  • threadWorkItem
  • 当我到达(b)时,我在线程 threadWorkItem 中(假设 threadWorkItem 是该线程的名称),因此我认为将另一个工作项排队到queueA没问题。但是有人说,此时,queueA被保留,queueA被阻止->导致死锁,这使我感到困惑

  • 我已经阅读了许多与此相关的主题,例如Deadlock with dispatch_syncWhy 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)有可用的工作线程,这不会导致死锁。但这是一个不好的做法,尽管如此,仍应避免。

    08-18 06:41