Deadlock — как правильно закрыть канал?

Deadlock — это ситуация, когда горутина блокируется, ожидая доступа к ресурсу, который никогда не будет освобожден. В языке программирования Go, существует несколько способов правильного закрытия каналов, чтобы избежать deadlock'ов.

Первый способ закрытия канала в Go — использование close() функции. Если вы вызываете эту функцию в горутине после завершения отправки значений в канал, то все завершится штатно. Пример:

func worker(input chan int, done chan bool) {
    defer func() {
        done <- true
    }()

    for num := range input {
        // ...
    }
}

func main() {
    input := make(chan int)
    done := make(chan bool)

    go worker(input, done)

    // отправляем значения в канал input

    close(input)

    // ожидаем завершения работы горутины
    <-done
}

В этом примере мы используем канал done, чтобы сообщить основной горутине о том, что горутина worker закончила выполнение. Перед завершением, горутина worker отправляет значение true в канал done. Основная горутина блокируется на операции <-done, пока не получит значения true.

Второй способ — использование варианта for range для чтения значений из канала. В этом случае, горутина продолжит исполнение цикла до тех пор, пока канал не будет закрыт. Пример:

func worker(input chan int, done chan bool) {
    defer func() {
        done <- true
    }()

    for num := range input {
        // ...
    }
}

func main() {
    input := make(chan int)
    done := make(chan bool)

    go worker(input, done)

    // отправляем значения в канал input

    // закрываем канал input
    close(input)

    // ожидаем завершения работы горутины
    <-done
}

В этом примере, горутина worker продолжает исполняться в цикле for num := range input, пока канал input не будет закрыт. При получении закрытого канала, цикл прекращается и горутина завершается.

Оба этих способа являются правильными и безопасными при закрытии каналов в Go. Они позволяют избежать deadlock'ов и гарантируют корректное завершение работы горутин.