Материал проходит вычитку — возможны неточности.
Урок 100 из 118

Источники синхронизации

На стендапе Миша выписал пять примитивов и для каждого вывел его ребро порядка. Сергей добавил под каждым пример из их кода. Старый код конфигурации не проходил ни через один из них.

Главная мысль

happens-before между горутинами дают пять примитивов — канал, мьютекс, Once, WaitGroup и атомики, и у каждого своё правило синхронизации.

Пять правил

  • Канал. Отправка happens-before завершением приёма этого значения. Закрытие канала happens-before приёмом, который вернул нулевое значение из-за закрытия. Для небуферизованного канала есть и обратное ребро: приём happens-before завершением отправки.
  • Мьютекс. Unlock happens-before последующим Lock. RWMutex: Unlock писателя happens-before последующим RLock читателей; RUnlock happens-before последующим Lock писателя. Между параллельными читателями ребра нет — оно и не нужно: они только читают.
  • Once. Завершение функции внутри Do happens-before возвратом всех Do того же Once.
  • WaitGroup. Вызов Done happens-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 не получает синхронизации автоматически — читатель должен пройти через тот же атомик или другую синхронизацию.

В следующем уроке

Вы узнаете:

  • где точные формулировки правил модели памяти
  • какое обратное ребро у буферизованного канала
Задание · вопросы

Проверьте себя

Вопрос 1 из 3

Какое ребро happens-before даёт пара мьютекса Unlock → Lock?

Вопрос 2 из 3

Какое ребро даёт sync.Once?

Вопрос 3 из 3

Есть ли ребро happens-before между параллельными читателями RWMutex?

Итоги

Пять примитивов — пять правил happens-before. Вместе с порядком программы и транзитивностью они дают строгий вывод о видимости в любом конкурентном коде.

Наш сайт собирает куки. Чтобы тебе было удобнее им пользоваться. Нажимая на кнопку, ты даёшь разрешение собирать куки