猿问

golang中不正确的同步

当我查看 golang 内存模型文档(链接)时,我在 go lang 上发现了一个奇怪的行为。该文档说下面的代码可能会发生 g 打印 2 然后打印 0。


var a, b int


func f() {

    a = 1

    b = 2

}


func g() {

    print(b)

    print(a)

}


func main() {

    go f()

    g()

}

这只是常规问题吗?因为我很好奇为什么变量 'b' 的值分配可以在 'a' 之前发生?即使 'a' 和 'b 的赋值发生在不同的线程中(不在主线程中),是否必须确保在它自己的线程中在 'b' 之前分配 'a'?(因为 ' a' 先出现,然后 'b' 出现)有人能清楚地告诉我这个问题吗?


蝴蝶刀刀
浏览 179回答 1
1回答

梦里花落0921

在任何函数开始执行之前,变量a和b使用它们各自类型的零值(0在 的情况下int)进行分配和初始化,在这一行:var a, b int可能会改变的是在f()函数中为它们分配新值的顺序。引用该页面:之前发生:在单个 goroutine 中,读取和写入必须按照程序指定的顺序执行。也就是说,只有当重新排序不会改变语言规范定义的 goroutine 中的行为时,编译器和处理器才可以重新排序在单个 goroutine 中执行的读取和写入。由于这种重新排序,一个 goroutine 观察到的执行顺序可能与另一个 goroutine 感知的顺序不同。例如,如果一个 goroutine 执行a = 1; b = 2;,另一个可能会在 的更新值b之前观察 的更新值a。如果重新排序它们不会在同一个 goroutine 中产生影响a,b则分配给和可能不会按照您编写它们的顺序发生。例如,如果首先更改 的值b更有效(例如,因为其地址已加载到寄存器中),则编译器可能会对它们重新排序。如果更改赋值顺序会(或可能)在同一个 goroutine 中导致问题,那么显然编译器不允许更改顺序。由于f()函数的 goroutine 对变量不做任何处理,a并且b在赋值之后,编译器可以自由地以任何顺序执行赋值。由于上述示例中的 2 个 goroutine 之间没有同步,因此编译器不会检查重新排序是否会导致其他 goroutine 出现任何问题。它没有必要。Buf 如果你同步你的 goroutines,编译器会确保在“同步点”没有不一致:你将保证在那个点两个分配都将“完成”;因此,如果“同步点”在print()调用之前,那么您将看到分配的新值打印:2和1。
随时随地看视频慕课网APP

相关分类

Go
我要回答