golang编译器什么时候可以重新排序命令,同步基元有什么影响?

问题描述 投票:0回答:1

我读过 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的角度来看,就不能从文中提到的保证中推断出来。

所以我的问题是:是否还有其他的保证在这个文档中没有明确说明?例如,我们是否可以说,给定一些同步基元,例如在通道上发送,保证放在它之前的命令,不会被编译器移到它之后?那在它之后的命令呢,我们能说它们不会被放在同步基元之前吗?

原子包中提供的操作呢?它们是否提供了和通道操作一样的保证?

go concurrency race-condition goroutine memory-model
1个回答
2
投票

我们是否可以说,给定一些同步基元,比如在通道上发送,确保放在它之前的命令不会被编译器移到它之后?

这正是内存模型所说的。当你看一个单一的goroutine时,可以重新安排执行顺序,使写操作的效果按照它们在执行中出现的顺序可见。因此,如果你设置 a=1 某时某刻,读到 a 后,编译器就知道不要把写操作移到读操作之前。对于多个goroutine来说,通道和锁是同步点,所以一旦达到同步点,在channellock操作之前发生的任何事情对其他goroutine都是可见的。编译器不会移动代码,使写操作越过同步边界。

同步操作也有满足的保证,并且一直在讨论是否将它们添加到内存模型中。目前还没有明确说明这些问题。有一个关于它的公开问题。

https:/github.comgolanggoissues5045。

© www.soinside.com 2019 - 2024. All rights reserved.