Как работают мьютексы, зачем они нужны и в чем их физический смысл
Что проверяют
Знаете ли вы, что происходит под Lock(), а не только как его вызвать: атомарные инструкции, парковка горутин, гарантии видимости памяти. Следом обычно просят сравнить sync.Mutex с RWMutex и каналами или показать, откуда берётся дедлок.
Как отвечать
Зачем он нужен: counter++ не атомарна, это чтение, сложение и запись. Две горутины на разных ядрах читают одно значение, и одно приращение теряется. Мьютекс превращает участок кода в критическую секцию, где в каждый момент находится одна горутина.
Как устроен sync.Mutex:
- быстрый путь: поле состояния меняется одной атомарной операцией compare-and-swap. Свободный мьютекс захватывается за наносекунды без участия планировщика;
- спин: на многоядерной машине горутина недолго крутится в ожидании, надеясь, что владелец скоро отпустит замок;
- парковка: дальше горутина засыпает на семафоре рантайма. Спит горутина, а не поток ОС, поток уходит выполнять другие горутины;
- режим голодания: если ожидающий ждёт дольше 1 мс, мьютекс переходит в честный режим и передаётся строго по очереди.
Физический смысл в двух вещах. Атомарность обеспечивает процессор: инструкция вроде LOCK CMPXCHG на x86 делает чтение и запись неделимыми для всех ядер. Вторая часть это барьер памяти. По модели памяти Go Unlock происходит раньше следующего Lock, поэтому записанное внутри секции гарантированно увидит следующая горутина, а не устаревшее значение из кеша ядра.
Практика: нулевое значение sync.Mutex готово к работе, освобождают через defer mu.Unlock(), секцию держат короткой. Если чтений намного больше записей, берут sync.RWMutex, для простых счётчиков sync/atomic.
Где спотыкаются
Копируют мьютекс: передают структуру с ним по значению или вешают методы на value receiver. Копия это отдельный замок, защита молча пропадает. Такое ловит go vet.
Ждут реентерабельности. Повторный Lock() в той же горутине вешает её навсегда, рекурсивных мьютексов в Go нет.
Проверяют код без -race. Гонка может месяцами не проявляться, а go test -race находит её, как только конкурентный путь хоть раз выполнился в тесте.