Понимание взаимоблокировки при вложенных вызовах DispatchQueue - PullRequest
0 голосов
/ 30 апреля 2020

У меня есть 2 аналогичных случая, первый

let queue1 = DispatchQueue(label: "queue1")
let queue2 = DispatchQueue(label: "queue2")

queue1.sync {
   print(1, Thread.current)

   queue2.sync {
      print(2, Thread.current)
   }

   print(3, Thread.current)
}

// result
1 <NSThread: 0x600001700140>{number = 1, name = main}
2 <NSThread: 0x600001700140>{number = 1, name = main}
3 <NSThread: 0x600001700140>{number = 1, name = main}

и второй

queue1.sync {
   print(1, Thread.current)

   DispatchQueue.main.sync {
      print(2, Thread.current)
   }

   print(3, Thread.current)
}

// result
1 <NSThread: 0x60000170c8c0>{number = 1, name = main}
deadlock

Как мы видим, в первом случае используются 2 последовательные очереди, все блоки вызываются на главном нить без тупика. Во втором случае используются 2 последовательные очереди (одна, если они являются основной очередью), а также вызывается в основном потоке, но теперь это вызывает взаимоблокировку. Так в чем же разница?

1 Ответ

3 голосов
/ 30 апреля 2020

Когда вы отправляете задачу с .sync(), текущий поток (независимо от того, какой именно) должен ждать, пока задача не будет завершена, потому что это точка .sync(). Учитывая, что поток заблокирован от продолжения, после того, как очереди, в которую он был отправлен, разрешено выполнять задачу, он фактически будет работать прямо в потоке, который вызвал .sync(). GCD не нужно набирать поток из пула потоков, потому что есть известный поток. (Это не гарантируется как таковое. Это оптимизация. Но это объясняет, почему в вашем первом фрагменте все задачи выполняются в главном потоке.)

В вашем втором фрагменте, однако, моя фраза "однажды Очередь […] разрешено запускать задание »вступает в силу. В основной очереди уже выполняется что-то: вызов queue1.sync(). Основная очередь не может запускать другую задачу до тех пор, пока она не завершится, потому что она последовательная. (Обратите внимание, что основная очередь и основной поток, хотя и тесно связаны, не одно и то же.) Поэтому задача, выполняемая в главной очереди, блокируется, ожидая завершения задачи, выполняющейся в главной очереди. Следовательно, тупик.

...