Выбор ответа 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.
Варианты ответа
- Нет happens-before: done можно вынести из цикла, записи переупорядочитьправильный ответ
- Нужно
runtime.Gosched()в цикле, тогда код станет корректным - Код корректен, потому что запись bool атомарна на всех поддерживаемых платформах
- Нужно объявить done как volatile, как в Java или C
Разбор
Модель памяти Go гарантирует видимость только через синхронизацию: каналы, мьютексы, atomic, WaitGroup. Здесь гонка данных: компилятор может прочитать done один раз и крутить вечный цикл, а читатель может увидеть done == true раньше, чем data. Gosched не создаёт happens-before. volatile в Go нет. Правильно: atomic.Bool для флага (атомарные операции синхронизируют и data) или закрытие канала.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.
Ещё по теме «sync и атомики»
- Глобальный максимум через CompareAndSwap
- Конкурентные переводы между счетами без дедлока
- Шардированная мапа с мьютексом на шард
- Что выведет Go: atomic.Int64 из 100 горутин
- Что выведет Go: sync.Once и OnceValue
- Код-ревью Go: кеш на RWMutex
- Код-ревью Go: ленивый синглтон и горячая перезагрузка конфига
- Типизированные атомики