Какие методы есть у мьютекса и их назначение в Go
Что проверяют
Знаете ли вы API sync.Mutex дальше пары Lock и Unlock и понимаете ли его семантику. Обычно продолжают так: чем отличается RWMutex, можно ли разблокировать мьютекс из другой горутины и почему для счётчика лучше atomic.
Как отвечать
Сначала методы:
Lock(): захватывает мьютекс. Если занят, горутина приостанавливается: планировщик снимает её с потока, и поток не простаивает;Unlock(): освобождает. Разблокировка незаблокированного мьютекса это паникаsync: unlock of unlocked mutex;TryLock() bool: есть в стандартной библиотеке с Go 1.18, берёт лок, если свободен, иначе сразу возвращаетfalse. В документации прямо сказано, что нужен он редко;sync.RWMutex:RLockиRUnlockдля читателей,LockиUnlockдля писателя, есть иTryRLock. Читатели работают параллельно, писатель эксклюзивно, ожидающий писатель не пускает новых читателей.
Дальше свойства, ради которых вопрос и задают: нулевое значение готово к работе, инициализация не нужна; мьютекс не рекурсивный, повторный Lock в той же горутине это дедлок; он не привязан к горутине, захватить может одна, освободить другая; копировать после использования нельзя, go vet ловит это проверкой copylocks. С Go 1.9 работает режим голодания: если горутина ждёт дольше 1 мс, мьютекс переходит в честный FIFO-режим.
Практика: mu.Lock() и defer mu.Unlock() в начале метода, секция короткая, никаких сетевых вызовов под локом. Для счётчиков дешевле atomic.Int64, для разовой инициализации есть sync.Once, гонки ловит go test -race.
Где спотыкаются
Ставят defer mu.Unlock() в длинной функции или внутри цикла. В первом случае лок держится до выхода из функции, во втором накапливается до конца цикла. Секцию выносят в отдельную функцию или зовут Unlock явно.
Считают RWMutex универсально более быстрым. На коротких секциях он проигрывает обычному Mutex из-за более дорогой синхронизации, выигрыш появляется только при долгих и частых чтениях.
Возвращают наружу ссылку на защищённые данные, слайс или карту, и считают их по-прежнему защищёнными. Мьютекс защищает не память, а участок кода: возвращённую ссылку читают и меняют уже без лока.