Mutex: защитить данные
Счётчики статистики конвейера врали: обработанных файлов оказывалось меньше, чем отправленных. Причина — десятки воркеров обновляли счётчики одновременно, и часть увеличений терялась. Миша закрыл общее состояние замком, и цифры сошлись.
мьютекс защищает данные, а не код: Lock/Unlock вокруг критической секции гарантируют, что в секции в каждый момент времени не больше одной горутины.
Общее состояние
type Stats struct {
mu sync.Mutex
processed int
}
func (s *Stats) Inc() {
s.mu.Lock()
s.processed++
s.mu.Unlock()
}
Счётчик статистики, который увеличивают из нескольких горутин, без защиты теряет инкременты — это data race. Мьютекс сериализует доступ: пока одна горутина в секции, остальные ждут на Lock.
Defer Unlock
func (s *Stats) Inc() {
s.mu.Lock()
defer s.mu.Unlock()
s.processed++
}
defer mu.Unlock — идиома, а не украшение. Критическая секция часто заканчивается return в нескольких местах или паникой, и defer гарантирует, что мьютекс отпустят на любом пути. Забытый Unlock в ветке с ранним выходом — один из самых коварных багов: он не падает сразу, а вешает следующую горутину.
Мьютекс защищает данные, не код
Мьютекс — это «замок на дверь к данным», а не «запрет выполнять функцию». Точнее говоря: мьютекс защищает инвариант данных. Пока все обращения к s.processed проходят через Lock, инвариант «processed согласован» держится. Если какая-то горутина пишет в s.processed в обход мьютекса, защита рушится — мьютекс не знает про данные, он знает про дисциплину обращений.
Вы узнаете:
- как happens-before работает через Unlock и Lock
- почему мьютекс кладут в структуру рядом с данными
Проверьте себя
Что защищает мьютекс?
Почему Unlock идиоматично делать через defer?
Метод возвращает внутренний слайс из-под мьютекса. Что это?
правильных ответов
Мьютекс сериализует доступ к общему состоянию: Lock/Unlock вокруг секции, Unlock — через defer. Защита держится на том, что все обращаются только под мьютексом.
10 000 ₽ · 60 минут · онлайн