Загрузка…
Загрузка…
Go · junior · сложность 2
Взаимная блокировка — это ситуация, когда две или более горутины блокируются на неопределенный срок, ожидая друг от друга освобождения ресурса или выполнения действия. В Go взаимоблокировки часто возникают, когда горутины ожидают каналов или мьютексов в циклической зависимости.
Идентификация:
Среда выполнения Go часто может обнаруживать глобальные взаимоблокировки (когда все горутины заблокированы) и завершает программу с «фатальной ошибкой: все горутины спят — взаимоблокировка!» сообщение вместе со трассировкой стека.
Анализ трассировки стека аварийной программы является ключом к идентификации горутин и каналов/мьютексов, которые они ожидают.
Инструменты профилирования и ручная проверка кода также необходимы в сложных случаях или частичных взаимоблокировках.
Предотвращение:
Постоянный порядок блокировок: При использовании нескольких мьютексов всегда получайте их в одном и том же порядке.
Избегайте ненужных блокировок: Минимизируйте критический раздел, защищенный мьютексом.
Таймаут/Отмена: Используйте context с таймаутами или сигналами отмены для операций, которые могут блокироваться на неопределенный срок (например, прием из канала).
Тщательное проектирование каналов: Убедитесь, что каналы правильно закрываются, когда значения больше не отправляются, и что горутины не остаются в ожидании на каналах, которые никогда не получат значения.
Избегайте циклических зависимостей. Разрабатывайте шаблоны взаимодействия так, чтобы избежать ситуаций, когда горутина A ожидает B, а B — A.
Пример (deadlock канала):
package main
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
val := <-ch1 // Goroutine 1 waits for ch1
ch2 <- val // Then sends to ch2
}()
// This main goroutine waits for ch2, but nothing is ever sent to ch1
// for Goroutine 1 to proceed.
val := <-ch2 // Deadlock: main waits for ch2, Goroutine 1 waits for ch1
println(val) // Unreachable
}
```
## Разбор
*Пояснение:* Основная горутина ожидает приема от `ch2`. Горутина 1 ожидает приема от `ch1`, прежде чем она сможет отправить что-либо на `ch2`. Поскольку на `ch1` ничего не отправляется, горутина 1 никогда не запускается, а основная горутина вечно ожидает на `ch2`.
## Итог
Взаимная блокировка — это ситуация, когда две или более горутины блокируются на неопределенный срок, ожидая друг от друга освобождения ресурса или выполнения действия.