Ответ
Вызов sync на serial (последовательной) очереди может привести к взаимной блокировке (deadlock), если этот вызов выполняется из той же самой очереди.
Причина deadlock:
- Метод
syncблокирует текущий поток до полного выполнения переданного блока кода. - Serial очередь выполняет задачи строго по одной.
- Если очередь уже выполняет какую-то внешнюю задачу (например, из предыдущего
async), она не может начать новую задачу (блок изsync), так как занята. - Внешняя задача, в свою очередь, ждет завершения
sync, создавая циклическую зависимость.
Пример deadlock:
let serialQueue = DispatchQueue(label: "com.example.serial")
serialQueue.async { // Задача A начинает выполняться на очереди
// Пока выполняется эта задача A, мы пытаемся отправить sync...
serialQueue.sync { // Задача B: DEADLOCK! Очередь не может начать B, пока не завершит A.
print("Этот код никогда не выполнится")
}
}
Как избежать:
- Не вызывайте
DispatchQueue.syncиз той же serial очереди, на которую вы его отправляете. - Используйте
asyncдля фоновых задач или отправляйтеsyncна другую очередь. - Для concurrent (параллельных) очередей такой проблемы нет.
Ответ 18+ 🔞
Ну, слушай, вот есть у тебя эта самая serial (последовательная) очередь. Представь её как узкий хуёвый коридор, где может идти только один человек за раз. Так вот, если ты изнутри этого коридора начнёшь орать «стой, блядь, на месте, пока я не пройду!» — это и есть вызов sync из той же очереди. И знаешь, что будет? Взаимная блокировка, ёпта, deadlock! Полный пиздец.
А почему так, спросишь? Всё просто, как три копейки:
- Метод
sync— это такой упырь, который блокирует текущий поток и не отпускает, пока переданный ему блок кода не отработает до конца. - Serial очередь — она же последовательная, сука. Одна задача, потом другая, строгая очередь, без самотёка.
- Вообрази: очередь уже занята выполнением какой-то внешней задачи (скажем, из предыдущего
async). Она не может взять новую задачу (наш блок изsync), потому что у неё рот и так уже занят. - А внешняя-то задача ждёт, когда же этот ёбаный
syncзавершится. И получается циклическая зависимость — они друг друга ждут, как два идиота в дверном проёме. В рот меня чих-пых!
Вот тебе наглядный пиздец в коде:
let serialQueue = DispatchQueue(label: "com.example.serial")
serialQueue.async { // Задача A начинает выполняться на очереди
// Пока выполняется эта задача A, мы пытаемся отправить sync...
serialQueue.sync { // Задача B: DEADLOCK! Очередь не может начать B, пока не завершит A.
print("Этот код никогда не выполнится")
}
}
Видишь? Задача А говорит: «Я не закончусь, пока не выполнится sync». А очередь ей: «Да пошла ты нахуй, я занята тобой, я не могу начать sync». И всё, приехали. Код завис, как мудак в лифте.
Как не наступить на эти грабли?
- Главное правило, блядь: не вызывай
DispatchQueue.syncиз той же самой serial очереди, на которую ты его отправляешь. Это как пытаться самому себя выебать — неебически сложно и противоестественно. - Используй
asyncдля фоновых дел — он не блокирует, он просто ставит в очередь и пошёл дальше. - Или отправляй свой
syncна совершенно другую очередь. Пусть они там друг друга блокируют. - Кстати, с concurrent (параллельными) очередями такой хуйни обычно не случается — там коридор пошире, народ может идти одновременно, так что один может другого и подождать. Но это уже другая история.