Источники синхронизации
На стендапе Миша выписал пять примитивов и для каждого вывел его ребро порядка. Сергей добавил под каждым пример из их кода. Старый код конфигурации не проходил ни через один из них.
happens-before между горутинами дают пять примитивов — канал, мьютекс, Once, WaitGroup и атомики, и у каждого своё правило синхронизации.
Пять правил
- Канал. Отправка happens-before завершением приёма этого значения. Закрытие канала happens-before приёмом, который вернул нулевое значение из-за закрытия. Для небуферизованного канала есть и обратное ребро: приём happens-before завершением отправки.
- Мьютекс.
Unlockhappens-before последующимLock. RWMutex:Unlockписателя happens-before последующимRLockчитателей;RUnlockhappens-before последующимLockписателя. Между параллельными читателями ребра нет — оно и не нужно: они только читают. - Once. Завершение функции внутри
Dohappens-before возвратом всехDoтого жеOnce. - WaitGroup. Вызов
Donehappens-before возвратомWait. - Атомики. Атомарная операция — точка синхронизации, как
Unlockдля последующегоLock.
Как это применять
var mu sync.Mutex
var data map[string]int
// писатель:
mu.Lock()
data = newData
mu.Unlock()
// читатель:
mu.Lock()
snapshot := data
mu.Unlock()
Если Lock читателя следует за Unlock писателя, то Unlock писателя happens-before Lock читателя — значит, запись data = newData видна в snapshot. Никакого «а вдруг не успело»: правила синхронизации это гарантируют. А если читатель возьмёт мьютекс первым — он увидит старую карту: гонки нет, но и свежести нет. Заметь: snapshot:= data копирует заголовок карты, а не данные — это общая ссылка на ту же карту, поэтому и читатели, и любые мутации обязаны идти под тем же мьютексом.
Атомики — последовательная согласованность
Про атомики в модели памяти сказано чуть больше: все атомарные операции программы ведут себя так, будто выполнялись в одном общем порядке, который наблюдают все горутины. Это называют последовательной согласованностью. Но атомарность касается только самих атомарных операций: обычная запись x = 1 рядом с atomic.Store не получает синхронизации автоматически — читатель должен пройти через тот же атомик или другую синхронизацию.
Вы узнаете:
- где точные формулировки правил модели памяти
- какое обратное ребро у буферизованного канала
Проверьте себя
Какое ребро happens-before даёт пара мьютекса Unlock → Lock?
Какое ребро даёт sync.Once?
Есть ли ребро happens-before между параллельными читателями RWMutex?
правильных ответов
Пять примитивов — пять правил happens-before. Вместе с порядком программы и транзитивностью они дают строгий вывод о видимости в любом конкурентном коде.
10 000 ₽ · 60 минут · онлайн