我读过 https:/golang.orgrefmem但有些地方我还是不清楚。
例如,在 "通道通信 "一节中,它说:"写到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来说,通道和锁是同步点,所以一旦达到同步点,在channellock操作之前发生的任何事情对其他goroutine都是可见的。编译器不会移动代码,使写操作越过同步边界。
同步操作也有满足的保证,并且一直在讨论是否将它们添加到内存模型中。目前还没有明确说明这些问题。有一个关于它的公开问题。