Назад к вопросам
Junior
427
questionbank

Что такое дедлоки?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Дедлок (deadlock) в Golang возникает, когда две или более горутины оказываются в состоянии ожидания друг друга, так что ни одна из них не может продолжить выполнение. Это происходит, когда группа горутин одновременно ожидают освобождения ресурсов, которые удерживаются другими горутинами из этой же группы.

Наиболее распространенные причины дедлоков в Golang связаны с использованием каналов:

  • Отправка в незабуферизированный канал, когда нет принимающей горутины: Горутина, отправляющая данные, заблокируется до появления получателя. Если получателя нет, и ни одна другая горутина не может его создать или принять данные, возникает дедлок.
  • Прием из незабуферизированного канала, когда нет отправляющей горутины: Горутина, принимающая данные, заблокируется до появления отправителя. Если отправителя нет, и ни одна другая горутина не может отправить данные, возникает дедлок.
  • Отправка в заполненный буферизированный канал: Горутина заблокируется, пока в канале не появится место.
  • Прием из пустого буферизированного канала: Горутина заблокируется, пока данные не появятся в канале.

Если все горутины в программе заблокированы и ожидают друг друга, среда выполнения Golang обнаружит этот дедлок и завершит программу с сообщением об ошибке.

Пример простейшего дедлока с использованием канала:

// Основная горутина создает канал
ch := make(chan int)

// Попытка принять данные, когда никто не отправляет
// Это заблокирует главную горутину навсегда
<-ch

Пример дедлока с двумя горутинами и двумя каналами (классический "философы за столом"):

// Два канала
ch1 := make(chan int)
ch2 := make(chan int)

// Горутина 1: ждет ch1, затем шлет в ch2
go func() {
    <-ch1 // Блокируется, ждет отправки в ch1
    ch2 <- 1
}()

// Горутина 2: ждет ch2, затем шлет в ch1
go func() {
    <-ch2 // Блокируется, ждет отправки в ch2
    ch1 <- 1
}()

// Основная горутина заблокируется, если не отправить ничего в каналы,
// или подождать завершения других горутин.
// В данном случае обе горутины будут ждать друг друга вечно.
// Чтобы избежать дедлока при таком сценарии, нужно изменить логику работы,
// возможно, с использованием select для неблокирующего получения или отправки,
// или с использованием таймаутов.

Обнаружение и предотвращение дедлоков требует тщательного анализа взаимодействия горутин и правильного использования примитивов синхронизации, таких как каналы и mutex'ы.