Выбор ответа Senior sync и атомики обновлено

Флаг без синхронизации

Вопрос

Почему этот код некорректен, даже если на практике «работает»?

var data int
var done bool

go func() {
    data = 42
    done = true
}()
for !done {
}
fmt.Println(data)

Попробуйте сами

Выберите вариант, и откроется разбор.

Показать ответ и разбор

Коротко

Правильный ответ: Нет happens-before: done можно вынести из цикла, записи переупорядочить. Модель памяти Go гарантирует видимость только через синхронизацию: каналы, мьютексы, atomic, WaitGroup.

Варианты ответа

  1. Нет happens-before: done можно вынести из цикла, записи переупорядочитьправильный ответ
  2. Нужно runtime.Gosched() в цикле, тогда код станет корректным
  3. Код корректен, потому что запись bool атомарна на всех поддерживаемых платформах
  4. Нужно объявить done как volatile, как в Java или C

Разбор

Модель памяти Go гарантирует видимость только через синхронизацию: каналы, мьютексы, atomic, WaitGroup. Здесь гонка данных: компилятор может прочитать done один раз и крутить вечный цикл, а читатель может увидеть done == true раньше, чем data. Gosched не создаёт happens-before. volatile в Go нет. Правильно: atomic.Bool для флага (атомарные операции синхронизируют и data) или закрытие канала.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.