Какие режимы работы существуют у `sync.Mutex` в Go и в чем их различие?

Ответ

sync.Mutex в Go имеет два режима работы, которые он переключает автоматически для оптимизации производительности и справедливости:

  1. Нормальный режим (Normal mode)

    • Когда используется: Когда мьютекс свободен или конкуренция за него невысока.
    • Как работает: Горутины, запрашивающие мьютекс, сначала пытаются захватить его с помощью атомарных операций (spin-loop) в течение короткого времени. Это очень быстро, если мьютекс освобождается почти сразу, и позволяет избежать затрат на переключение контекста горутины. Если захватить мьютекс не удалось, горутина уходит в ожидание.
    • Недостаток: В этом режиме возможна ситуация "захвата на опережение" (barging), когда новая горутина может перехватить мьютекс у горутины, которая уже давно стоит в очереди.
  2. Режим голодания (Starvation mode)

    • Когда используется: Мьютекс переходит в этот режим, если горутина ожидает освобождения дольше 1 миллисекунды.
    • Как работает: В этом режиме мьютекс передается строго по очереди — от освободившей его горутины к той, что дольше всех ждет в очереди. Новые горутины не могут его захватить, даже если он свободен, а становятся в конец очереди.
    • Цель: Обеспечить справедливость и предотвратить ситуацию, когда некоторые горутины никогда не получают доступ к ресурсу.
package main

import "sync"

var mu sync.Mutex

func criticalSection() {
    mu.Lock() // Захват мьютекса. Горутина может войти в ожидание.
    // ... критическая секция ...
    mu.Unlock() // Освобождение мьютекса для других горутин.
}

Эта двухрежимная система позволяет sync.Mutex быть одновременно высокопроизводительным при низкой конкуренции и справедливым при высокой.