golang 编译器何时可以对命令重新排序,同步原语如何影响命令?



我已经读过 https://golang.org/ref/mem,但有些部分我仍然不清楚。

例如,在"通道通信"部分中,它说:"写入 a 发生在 c 上发送之前",但我不知道为什么会这样。我在下面复制从上述页面中提取的示例代码以提供上下文。

var c = make(chan int, 10)
var a string
func f() {
a = "hello, world"
c <- 0
}
func main() {
go f()
<-c
print(a)
}

从单个goroutine的角度来看,这个断言是正确的,但是从另一个goroutine的角度来看,这不能从文本到目前为止提到的保证中推断出来。

所以我的问题是:本文件中是否没有明确说明其他保证?例如,我们是否可以说给定一些同步原语(例如在通道上发送(,确保放置在它之前的命令不会被编译器移动到它之后?它后面的命令呢,我们可以说它们不会放在同步原语之前吗?

原子包中提供的操作呢?它们是否提供与渠道运营相同的保证?

我们可以说给定一些同步原语(例如在通道上发送(可确保放置在它之前的命令不会被编译器移动到它之后吗?

这正是记忆模型所说的。当您查看单个 goroutine 时,可以重新排列执行顺序,以便写入操作的效果按照它们在执行中出现的顺序可见。因此,如果您在某个时间点设置a=1并在稍后读取a,编译器知道不要将写入操作移动到读取之前。对于多个 goroutine,通道和锁是同步点,因此一旦达到同步点,在通道/锁定操作之前发生的任何事情对其他 goroutines 都是可见的。编译器不会移动代码,以便写入操作跨越同步边界。

同步/原子操作也满足保证,并且已经讨论了是否将它们添加到内存模型中。目前没有明确说明。有一个关于它的未决问题:

https://github.com/golang/go/issues/5045

最新更新