Что делает метод Lock в Go
Что проверяют
Понимаете ли вы, что Lock блокирует горутину до освобождения мьютекса, и знаете ли свойства sync.Mutex, на которых ломаются реальные программы. Следом почти всегда спрашивают про RWMutex или просят найти дедлок в куске кода.
Как отвечать
mu.Lock() захватывает мьютекс: если он свободен, вызов возвращается сразу, если занят, горутина ждёт, пока владелец не вызовет Unlock. Кроме взаимного исключения, пара даёт гарантию модели памяти: всё, что записано до Unlock, видно горутине после её Lock.
Свойства, которые стоит назвать:
- нулевое значение готово:
var mu sync.Mutexуже рабочий свободный мьютекс; - нереентерабельность: повторный
Lockв той же горутине безUnlockэто вечная блокировка; - нельзя копировать: структура с мьютексом, переданная по значению, копирует и его состояние. Это ловит
go vetпроверкойcopylocks; Unlockсвободного мьютекса: фатальная ошибка рантайма,recoverеё не перехватит;TryLock: есть с Go 1.18, но документация прямо предупреждает, что уместные сценарии для него редки.
Идиома: mu.Lock() и сразу defer mu.Unlock(), чтобы паника или ранний return не оставили мьютекс захваченным. Под капотом горутина может недолго покрутиться в спине, потом паркуется, а если ожидающий ждёт дольше 1 мс, мьютекс переходит в режим голодания и отдаёт владение строго по очереди.
У RWMutex много читателей держат RLock одновременно, а Lock ждёт ухода всех читателей и не пускает новых.
Где спотыкаются
Держат мьютекс во время сетевого вызова или отправки в канал. Критическая секция раздувается, и сервис упирается в одну горутину.
Защищают запись, но читают поле без Lock. go test -race находит это сразу, только его не запускают.
Возвращают из метода срез или map, защищённые мьютексом. Вызывающий код потом меняет их уже без блокировки.