【问题标题】:When can golang compiler reorder commands and how sync primitives affects that?golang 编译器何时可以重新排序命令以及同步原语如何影响它?
【发布时间】:2020-09-25 01:37:27
【问题描述】:

我已经阅读了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 的角度来看,不能从文本迄今为止提到的保证中推断出来。

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

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

【问题讨论】:

  • “是否有其他未在本文档中明确说明的保证” 否。规范和内存模型准确地说明了语言的预期。

标签: go concurrency race-condition goroutine memory-model


【解决方案1】:

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-15
    • 1970-01-01
    • 2016-06-23
    • 1970-01-01
    • 1970-01-01
    • 2015-03-02
    • 1970-01-01
    • 2020-05-08
    相关资源
    最近更新 更多