dispatch_sync中的dispatch_sync导致死锁

onm*_*133 4 deadlock sync dispatch grand-central-dispatch ios

我刚刚在objc.io上看到了这完全异步,但找不到好的解释

dispatch_queue_t queueA; // assume we have this
dispatch_sync(queueA, ^(){  // (a)
    dispatch_sync(queueA, ^(){ // (b)
        foo();
    });
});
Run Code Online (Sandbox Code Playgroud)

一旦我们点击了第二个dispatch_sync,我们就会死锁:我们无法调度到queueA,因为有人(当前线程)已经在该队列上并且永远不会离开它.

只要我明白

  1. dispatch_sync只需添加工作项(我避免使用"块",因为它可能会混淆)到queueA,然后这个工作项将被发送到queueA的目标队列,然后GCD将为此工作项保留一个线程 threadWorkItem
  2. 当我到达(b)时,我在线程threadWorkItem(假设threadWorkItem是这个线程的名称),所以我认为将另一个工作项排入队列是没有问题的.但有人说,此时,queueA被保留,queueA被阻止 - >导致死锁,这让我感到困惑

我已经阅读了很多与此相关的线程,比如使用dispatch_sync进行死锁,为什么我们不能在当前队列中使用dispatch_sync?,为什么这个dispatch_sync()调用冻结?,...但是找不到好的解释.有人说dispatch_sync阻止队列,有人说它阻止当前线程,...... :(

那为什么会导致僵局呢?

Rob*_*Rob 11

dispatch_sync块当前线程,直到被派遣代码完成,如果你正在从同步串行队列调度,您因此被有效地阻止了队列,太.因此,如果您从串行队列同步调度到自身,则会导致死锁.

但要明确,dispatch_sync阻止当前线程,而不是当前队列.处理并发队列时,不同的工作线程将用于随后调度的块,并且不会产生死锁.

您似乎正在响应" 并发编程指南"的" 调度队列"一章末尾的讨论,其中说:

不要dispatch_sync从传递给函数调用的同一队列上执行的任务调用该函数.这样做会使队列死锁.如果需要调度到当前队列,请使用该dispatch_async函数异步执行此操作.

这不完全正确.如果(a)您使用并发队列执行此操作; (b)有可用的工作线程,这不会导致死锁.但这是一种不好的做法,应该避免.

  • @entropy`dispsatch_sync`总是阻塞调用它的线程,等待调度的代码块完成.如果已经调度到某个串行队列的代码块本身尝试同步将另一个代码块分派到同一个队列,则第二个调度的代码块将永远不会启动,因为它在第一个块完成之前无法启动.但是由于它调用了`dispatch_sync`,第一个块被阻塞了. (3认同)