对《GO 高级编程》1.5 节面向并发的内存模型的理解问题

2018-08-14 13:43:51 +08:00
 flyingpine

go 初学者,在看《 GO 高级编程》,对于下面这句话不是很理解,

https://chai2010.gitbooks.io/advanced-go-programming-book/content/ch1-basic/ch1-05-mem.html

“更糟糕的是,因为两个线程之间没有同步事件,setup 线程对 done 的写入操作甚至无法被 main 线程看到,main 函数有可能陷入死循环中。”

var a string
var done bool
func setup() {
	a = "hello, world"
	done = true
}
func main() {
	go setup()
	for !done {}
	print(a)
}

在 main 的 for 循环里检查 done 的值,即使某一次检查恰好与 setup 设置 done 相冲突,在下次 for 的检查应该也能发现 done 被设为 true 了啊,为什么会说“ setup 线程对 done 的写入操作甚至无法被 main 线程看到”呢?

1067 次点击
所在节点    问与答
3 条回复
mind3x
2018-08-14 15:34:51 +08:00
请搜索“内存模型”
简单的说,现代 CPU 的乱序执行特性使得有可能 done=true 发生在 a 赋值以前。
flyingpine
2018-08-14 16:34:56 +08:00
@mind3x 多谢回复,是的,这个可以解释前一句话:“但是 Go 语言并不保证在 main 函数中观测到的对 done 的写入操作发生在对字符串 a 的写入的操作之后,因此程序很可能打印一个空字符串。” 对于我的问题,刚才又读了很多文档,一个可能的解释是 main thread 的空循环会导致 CPU 不能被调度到 setup,所以 setup 一直得不到执行。
gamexg
2018-08-14 18:12:35 +08:00
是的,除了你说的还有另外一个可能:

我对汇编忘的差不多了,
编译器可能会优化成这样:main 将 done 的值读到了寄存器,之后循环全部是从寄存器读取的,并未去读取内存,所以可能永远不知道 setup 的变更。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/479669

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX