Какие примитивы синхронизации существуют и как они работают
Что проверяют
Знаете ли вы, что в Go основной инструмент это каналы, и понимаете ли, когда всё-таки нужен мьютекс.
Как отвечать
Начните с принципа: «не общайтесь, разделяя память, разделяйте память, общаясь». Канал это и синхронизация, и передача данных одновременно.
Что есть в sync и sync/atomic:
- Mutex: взаимное исключение. Защищает участок, где меняется общая структура. Не реентрантный: повторный захват тем же горутиной это взаимная блокировка;
- RWMutex: много читателей или один писатель. Выигрывает при явном перевесе чтений, иначе накладные расходы съедают пользу;
- WaitGroup: дождаться завершения группы горутин.
Addдо запуска,Doneчерезdefer; - Once: ленивая инициализация ровно один раз, даже при гонке;
- Cond: ожидание условия, нужен редко, обычно заменяется каналом;
- atomic: атомарные операции над числами и указателями без блокировок, а также типизированные
atomic.Int64иatomic.Value; - errgroup: группа горутин с отменой по первой ошибке, из
golang.org/x/sync; - семафор на канале: буферизованный канал как ограничитель одновременных операций.
Правило выбора: передаёте владение данными, берите канал; защищаете общую структуру от параллельного доступа, берите мьютекс; считаете счётчик, берите atomic.
И обязательно назовите инструмент: go test -race и запуск с -race в тестовой среде. Гонки в Go находят детектором, а не чтением кода.
Где спотыкаются
Копируют структуру, содержащую мьютекс, и получают две независимые блокировки.
Пытаются захватить мьютекс повторно.
Ставят RWMutex везде, не замерив соотношение чтений и записей.
Не гоняли тесты с детектором гонок.