Ответ
Deadlock (взаимная блокировка) — это ситуация в многопоточной системе, когда две или более горутины находятся в состоянии бесконечного ожидания, поскольку каждая из них ожидает ресурс, занятый другой горутиной из этой же группы.
Для возникновения deadlock необходимо одновременное соблюдение четырёх условий (условия Коффмана):
- Взаимное исключение (Mutual Exclusion): Ресурс в каждый момент времени может быть занят только одной горутиной.
- Удержание и ожидание (Hold and Wait): Горутина удерживает как минимум один ресурс и запрашивает другие ресурсы, которые в данный момент заняты другими горутинами.
- Отсутствие вытеснения (No Preemption): Ресурс не может быть принудительно отобран у горутины; он может быть освобожден только той горутиной, которая его захватила.
- Кольцевое ожидание (Circular Wait): Существует цепочка из двух или более горутин, где каждая ожидает ресурс, удерживаемый следующей горутиной в цепочке.
Классический пример на Go:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var mu1, mu2 sync.Mutex
var wg sync.WaitGroup
wg.Add(2)
// Горутина 1: захватывает mu1, затем пытается захватить mu2
go func() {
defer wg.Done()
mu1.Lock()
fmt.Println("Горутина 1: захватила mu1")
time.Sleep(100 * time.Millisecond) // Даем время второй горутине захватить mu2
mu2.Lock()
fmt.Println("Горутина 1: захватила mu2")
mu2.Unlock()
mu1.Unlock()
}()
// Горутина 2: захватывает mu2, затем пытается захватить mu1
go func() {
defer wg.Done()
mu2.Lock()
fmt.Println("Горутина 2: захватила mu2")
time.Sleep(100 * time.Millisecond)
mu1.Lock() // <- Здесь произойдет deadlock
fmt.Println("Горутина 2: захватила mu1")
mu1.Unlock()
mu2.Unlock()
}()
wg.Wait()
}
Способы предотвращения deadlock:
- Соблюдение порядка блокировок: Всегда захватывать мьютексы в одном и том же строгом порядке (например, сначала
mu1
, потомmu2
во всех горутинах). - Использование таймаутов: Пытаться захватить блокировку с таймаутом (например, с помощью
select
иtime.After
), чтобы избежать вечного ожидания. - Использование
sync.RWMutex
: Позволяет множественные блокировки на чтение, снижая вероятность конфликтов.