Почему случается deadlock

Ответ

Deadlock возникает, когда два или более потока блокируют друг друга, ожидая ресурсы, занятые другим потоком. Основные условия:

  1. Взаимное исключение - ресурс занят одним потоком
  2. Удержание и ожидание - поток держит ресурс и ждёт другой
  3. Нет вытеснения - ресурсы нельзя отнять
  4. Циклическое ожидание - потоки ждут друг друга по кругу

Пример:

let lock1 = NSLock()
let lock2 = NSLock()

DispatchQueue.global().async {
    lock1.lock()
    sleep(1)
    lock2.lock() // Ждёт lock2, но он занят вторым потоком
    lock2.unlock()
    lock1.unlock()
}

DispatchQueue.global().async {
    lock2.lock()
    sleep(1)
    lock1.lock() // Ждёт lock1, но он занят первым потоком
    lock1.unlock()
    lock2.unlock()
}

Ответ 18+ 🔞

А, слушай, смотри, вот тебе классика жанра, блядь — deadlock! Это когда два потока, такие два упыря, взяли друг друга за горло и оба не дышат, сука. Как два мужика в подъезде, которые друг другу не уступают, а проход-то один, блядь. И стоят, ебать, до посинения.

Вот смотри, условия, блядь, чтоб этот цирк начался:

  1. Взаимное исключение, ну это понятно — один взял ресурс, второй уже не лезь, пиздец, занято.
  2. Удержание и ожидание — это гениально, блядь! Чувак держит одну штуку в руке, а второй рукой тянется за другой, которую уже кто-то схватил. И не отпускает первую, хитрая жопа! "Моё, и то тоже моё будет!"
  3. Нет вытеснения — отжать не получится, как в хорошей драке. Ресурс добровольно не отдаст, пока сам не захочет.
  4. Циклическое ожидание — вот тут пиздец начинается. Получается хоровод, блядь, ёперный театр! Первый ждёт от второго, второй ждёт от первого, и поехали... В рот меня чих-пых!

И вот тебе наглядный пиздец в коде, смотри, как они друг другу жизнь портят:

let lock1 = NSLock() // Первый замок, блядь
let lock2 = NSLock() // Второй замок, ёпта

DispatchQueue.global().async {
    lock1.lock() // Первый чувак схватил первый замок. Молодец!
    sleep(1) // Покуривает, блядь, наслаждается жизнью
    lock2.lock() // А теперь тянется за вторым... Но, сука, он же уже занят! И стоит, блядь, как дурак.
    lock2.unlock()
    lock1.unlock()
}

DispatchQueue.global().async {
    lock2.lock() // А второй-то, падла, уже второй замок прихватил!
    sleep(1) // Тоже сидит, довольный, ебать его в сраку
    lock1.lock() // И ему захотелось первый... Который у первого! И тоже встал в позу.
    lock1.unlock()
    lock2.unlock()
}

И всё, приехали! Сидят два потока, у каждого по замку, и оба хотят чужой. И будут так висеть до скончания времён, пока система не прибьёт это безобразие. Красота, да? Прям как в жизни, блядь.