Перейти к содержимому
9 / 15

Модель памяти Go: happens-before, пакет atomic и почему без синхронизации нельзя

Модель памяти Go отвечает на один вопрос: при каких условиях чтение переменной в одной горутине гарантированно увидит запись из другой. Ответ формулируется через отношение happens-before: если запись не упорядочена перед чтением, компилятор и процессор вправе переставлять операции, кешировать значение в регистре и вообще не показывать его другой горутине. Именно поэтому цикл for !done {} может крутиться вечно, хотя другая горутина давно выставила done = true. Отношение создают только явные средства синхронизации: запуск горутины, отправка и приём по каналу, Mutex.Lock и Unlock, WaitGroup.Wait, Once.Do, операции пакета atomic. Практический вывод: атомарность и видимость — разные свойства. atomic.Int64.Add даёт и то и другое, а обычный n++ под защитой мьютекса — тоже, но n++ без всего не даёт ни того ни другого. Начиная с Go 1.19 у atomic есть типизированные обёртки вроде atomic.Bool и atomic.Pointer[T], и пользоваться следует ими.