Golang: writing to a variable has no effect in a goroutine if immediately followed by a `for{}` loop

huangapple go评论79阅读模式
英文:

Golang: writing to a variable has no effect in a goroutine if immediately followed by a `for{}` loop

问题

package main

import (
	"fmt"
	"time"
)

func main() {
	var x = 0
	go func() {
		x = 1
		for {
		}
	}()

	time.Sleep(5000 * time.Millisecond)
	fmt.Printf("%d", x)
}

为什么上面的代码会打印0

如果在for{}之前或之中添加任何内容,例如runtime.Gosched()print(x),它将按预期打印1

这与写屏障/先行发生关系吗?我完全困惑了。

我让另一个goroutine在打印值之前休眠了5秒钟。这不足以让写操作同步/缓存刷新/...吗?

英文:
package main

import (
	"fmt"
	"time"
)

func main() {
	var x = 0
	go func() {
		x = 1
		for {
		}
	}()

	time.Sleep(5000 * time.Millisecond)
	fmt.Printf("%d", x)
}

Why does the above code print 0?

If you add anything before or in the for{}, for example, runtime.Gosched(), print(x), it will print 1 as expected.

Is it related to write barrier / happened-before, or? I'm totally confused.

I made the other goroutine sleep for 5 seconds before printing the value. Isn't it enough time for the write to sync / cache to flush / ...?

答案1

得分: 3

感谢你的评论,Cerise。

~ go tool compile -S main.go
...
"".main.func1 STEXT nosplit size=3 args=0x0 locals=0x0 funcid=0x0
        0x0000 00000 (main.go:10)       TEXT    "".main.func1(SB), NOSPLIT|NEEDCTXT|ABIInternal, $0-0
        0x0000 00000 (main.go:10)       FUNCDATA        $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
        0x0000 00000 (main.go:10)       FUNCDATA        $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
        0x0000 00000 (main.go:12)       XCHGL   AX, AX
        0x0001 00001 (main.go:1)        JMP     0
        0x0000 90 eb fd                             

看起来,Golang编译器确实在汇编代码中删除了x = 1语句(应该是main.go:11)。

在编程时,我们确实需要牢记《Go内存模型》和《Happens Before》的原则。

英文:

Thanks for the comment, Cerise.

~ go tool compile -S main.go
...
"".main.func1 STEXT nosplit size=3 args=0x0 locals=0x0 funcid=0x0
        0x0000 00000 (main.go:10)       TEXT    "".main.func1(SB), NOSPLIT|NEEDCTXT|ABIInternal, $0-0
        0x0000 00000 (main.go:10)       FUNCDATA        $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
        0x0000 00000 (main.go:10)       FUNCDATA        $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
        0x0000 00000 (main.go:12)       XCHGL   AX, AX
        0x0001 00001 (main.go:1)        JMP     0
        0x0000 90 eb fd                             

Seems like golang compiler indeed deleted the x = 1 statement in the assembly (should be main.go:11).

We really need to keep The Go Memory Model and Happens Before in mind when programming.

huangapple
  • 本文由 发表于 2022年1月14日 14:04:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/70706600.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定