为什么这段代码是未定义行为?

huangapple go评论94阅读模式
英文:

Why is this code Undefined Behavior?

问题

这是一段Go代码。我的朋友告诉我这是UB(未定义行为)的代码。为什么呢?

英文:
  var x int
  done := false
  go func() { x = f(...); done = true }
  while done == false { }

This is a Go code piece. My fiend told me this is UB code. Why?

答案1

得分: 5

如在“为什么这个程序在我的系统上终止,但在playground上不终止?”中所解释的,

Go内存模型不能保证在goroutine中写入的值会被main程序观察到。
go routine destruction部分的示例中也给出了类似错误的程序。
Go内存模型还在该部分明确指出了没有同步的忙等待是一种错误的习惯用法。

在你的情况下,不能保证goroutine中写入的值会被main程序观察到。

在这里,你需要在goroutine中进行某种形式的同步,以确保done=truemain中的for循环的某个迭代之前发生。

while”(在Go中不存在)应该被替换为一个通道,你在其中阻塞(等待通信)。

for {
    <-c // 2
}

基于在main中创建的通道(c := make(chan bool)),并在goroutine中关闭(close(c))。


sync包提供了其他等待goroutine结束后再退出main的方法。

例如,参见Golang示例等待所有后台goroutine完成

var w sync.WaitGroup
w.Add(1)
go func() {
    // 做一些事情
    w.Done()
}
w.Wait()
英文:

As explained in "Why does this program terminate on my system but not on playground?"

> The Go Memory Model does not guarantee that the value written to x in the goroutine will ever be observed by the main program.
A similarly erroneous program is given as an example in the section on go routine destruction.
The Go Memory Model also specifically calls out busy waiting without synchronization as an incorrect idiom in this section.

(in your case, there is no guarantee that the value written to done in the goroutine will ever be observed by the main program)

Here, You need to do some kind of synchronization in the goroutine in order to guarantee that done=true happens before one of the iterations of the for loop in main.

The "while" (non-existent in Go) should be replaced by, for instance, a channel you block on (waiting for a communication)

for {
    &lt;-c // 2
}

Based on a channel (c := make(chan bool)) created in main, and closed (close(c)) in the goroutine.


The sync package provides other means to wait for a gorountine to end before exiting main.

See for instance Golang Example Wait until all the background goroutine finish:

var w sync.WaitGroup
w.Add(1)
go func() {
    // do something
    w.Done()
}
w.Wait()

huangapple
  • 本文由 发表于 2014年5月13日 21:03:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/23632072.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定