Вопрос проверяет понимание работы последовательных (serial) очередей в GCD (Grand Central Dispatch) и их взаимодействия с синхронными (sync) операциями.
Serial queue (последовательная очередь) в GCD гарантирует, что задачи выполняются строго одна за другой. Метод dispatch_sync (или sync в Swift) отправляет задачу в очередь и блокирует текущий поток до её завершения.
Если вызов sync происходит извне serial queue (например, из main thread или другой очереди), задача будет поставлена в конец serial queue и выполнится, как только очередь освободится. Текущий поток будет заблокирован на время выполнения этой задачи.
let serialQueue = DispatchQueue(label: "com.example.serial")
serialQueue.async {
print("Task 1")
}
// Вызов из main thread
serialQueue.sync {
print("Task 2") // Выполнится после Task 1
}
print("После sync") // Напечатается после завершения Task 2Проблема возникает, когда вызов sync выполняется из задачи, которая уже работает на этой же serial queue. Поскольку очередь последовательная, она не может начать новую задачу, пока не завершит текущую. Но текущая задача ждёт, пока новая задача запустится и завершится. Это взаимное ожидание приводит к deadlock.
let serialQueue = DispatchQueue(label: "com.example.serial")
serialQueue.async {
// Эта задача уже выполняется на serialQueue
serialQueue.sync {
print("Этот код никогда не выполнится")
}
print("Это тоже не выполнится")
}В этом примере внешняя асинхронная задача занимает serial queue. Внутри неё мы пытаемся синхронно отправить другую задачу в ту же очередь. Очередь ждёт завершения внешней задачи, но внешняя задача ждёт запуска внутренней — deadlock.
Понимание этого поведения критично для избежания deadlock в многопоточном коде. Serial queues часто используются для синхронизации доступа к общим ресурсам. Синхронные вызовы в них полезны, когда нужно дождаться результата, но их нужно использовать осторожно, избегая вызовов в ту же очередь изнутри.
Итог: Вызов sync внутри serial queue безопасен, если он выполняется не из задачи, работающей на этой же очереди. В противном случае это приводит к deadlock. Используйте async или убедитесь, что вызов идёт с другого потока/очереди.