В этом коде возможна ситуация бесконечного цикла. Переменная done изменяется в горутине, но в главной горутине нет механизма синхронизации или использования атомарных операций, чтобы гарантировать видимость изменений.
// Что будет выведено?
В этом коде возможна ситуация бесконечного цикла. Переменная done изменяется в горутине, но в главной горутине нет механизма синхронизации или использования атомарных операций, чтобы гарантировать видимость изменений.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
// Что будет выведено?
package main
import (
"fmt"
"runtime"
)
func main() {
runtime.GOMAXPROCS(1)
done := false
go func() {
done = true
}()
for !done {
}
fmt.Println("finished")
}
Ответ
В этом коде возможна ситуация бесконечного цикла. Переменная done изменяется в горутине, но в главной горутине нет механизма синхронизации или использования атомарных операций, чтобы гарантировать видимость изменений.
Из-за оптимизаций компилятора и кэширования CPU главный цикл for !done {} может никогда не увидеть обновление done = true из другой горутины, и программа зависнет в этом цикле.
Если убрать runtime.GOMAXPROCS(1), то есть позволить планировщику использовать несколько OS-потоков, то вероятность увидеть обновление выше, но не гарантирована без синхронизации.
Правильный способ — использовать каналы или синхронизацию из пакета sync/atomic.
Пример с каналом:
package main
import "fmt"
func main() {
done := make(chan struct{})
go func() {
done <- struct{}{}
}()
<-done
fmt.Println("finished")
}