Какие методы есть у локера в Go
Что проверяют
Знаете ли вы интерфейс sync.Locker и его реализации, а заодно правила, которые нарушают даже опытные разработчики. Следом обычно спрашивают, когда RWMutex выгоднее обычного мьютекса и можно ли захватить мьютекс повторно в той же горутине.
Как отвечать
Начните с интерфейса: sync.Locker описывает два метода, Lock() и Unlock(). Его реализуют:
sync.Mutex:Lock(),Unlock()и появившийся в Go 1.18TryLock(), который пробует захватить мьютекс без ожидания и возвращаетbool;sync.RWMutex:Lock()иUnlock()для записи,RLock()иRUnlock()для чтения,TryLock()иTryRLock(). МетодRLocker()возвращаетLocker, у которогоLockвызываетRLock, это пригодится дляsync.Cond.
Дальше правила:
- нулевое значение: готово к работе, конструктор не нужен;
- копирование: после первого использования запрещено, поэтому структуры с мьютексом передают по указателю, а
go vetловит ошибку проверкойcopylocks; - владелец: мьютекс не привязан к горутине, одна может захватить, другая освободить;
- лишний
Unlock(): освобождение незахваченного мьютекса даёт фатальную ошибку, которую не перехватитьrecover; - реентерабельность: её нет, повторный
Lock()в той же горутине это дедлок.
RWMutex выгоден, когда чтений намного больше, чем записей, и критическая секция не крошечная. На коротких операциях его накладные расходы съедают выигрыш. sync.Once и sync.WaitGroup локерами не являются, хотя их часто перечисляют рядом.
Стандартный шаблон: mu.Lock() и сразу defer mu.Unlock(), чтобы ранний return или паника не оставили мьютекс захваченным.
Где спотыкаются
Берут RLock() рекурсивно. Если между двумя захватами на чтение пришёл писатель, новый RLock() ждёт его, писатель ждёт первый, и получается дедлок.
Объявляют метод с получателем по значению у структуры с мьютексом. Каждый вызов работает с копией, и защита исчезает.
Строят логику на TryLock(). Документация прямо говорит, что корректные случаи его применения редки, и обычно это признак проблемы в дизайне.