Какие типы мьютексов предоставляет stdlib?go-90

Стандартная библиотека Go предоставляет два основных типа мьютексов в пакете sync:

1. sync.Mutex - обычный мьютекс

Характеристики:

  • Блокирующая реализация
  • Только эксклюзивная блокировка (либо одна горутина владеет, либо все ждут)
  • Не имеет приоритетов или очередей (не гарантируется порядок разблокировки)

Пример использования:

var mu sync.Mutex
var counter int

func increment() {
    mu.Lock()
    defer mu.Unlock()
    counter++
}

Особенности:

  • При вызове Lock() горутина блокируется, пока мьютекс не будет доступен
  • Unlock() должен вызываться той же горутиной, что и Lock()
  • Попытка повторного блокирования одной горутиной приведет к deadlock (не реентерабельный)

2. sync.RWMutex - читатель-писатель мьютекс

Характеристики:

  • Позволяет множественное чтение или эксклюзивную запись
  • Оптимизирован для сценариев "частое чтение, редкая запись"
  • Имеет два типа блокировок:
    • RLock()/RUnlock() - для читателей
    • Lock()/Unlock() - для писателей

Пример использования:

var rwmu sync.RWMutex
var data map[string]string

func readValue(key string) string {
    rwmu.RLock()
    defer rwmu.RUnlock()
    return data[key]
}

func writeValue(key, value string) {
    rwmu.Lock()
    defer rwmu.Unlock()
    data[key] = value
}

Преимущества RWMutex:

  • Множественные горутины могут одновременно читать данные
  • Только одна горутина может писать в любой момент времени
  • Писатель блокирует всех читателей и других писателей

Сравнение мьютексов

Характеристика sync.Mutex sync.RWMutex
Блокировка чтения Полная Множественная
Блокировка записи Полная Эксклюзивная
Производительность Базовая Выше для read-heavy
Сложность Проще Сложнее

Особенности реализации

  1. Нулевое значение мьютекса готово к использованию
  2. Не копировать мьютексы после первого использования
  3. Не реентерабельные - нельзя вызывать Lock из той же горутины повторно
  4. Нет таймаутов на блокировку (в отличие от других языков)

Пример deadlock

var mu sync.Mutex

func fatal() {
    mu.Lock()
    mu.Lock() // Deadlock - вторая блокировка в той же горутине
}

Резюмируем

стандартная библиотека Go предоставляет два типа мьютексов - обычный sync.Mutex для эксклюзивного доступа и sync.RWMutex для оптимизированного read-heavy доступа. Выбор между ними зависит от паттерна доступа к защищаемым данным.