最近复习,遇到go内存模型的问题,心中一直以为硬件是会保证缓存和内存一致性的。不过看了不少例子有很多困惑,关于happend before之外的困惑。之后就又查了不少硬件内存模型的文章。这里就记录一下一些不错的文章,再对几个例子做一些硬件体系上的汇总,不再详细说明go的内存模型了,毕竟关于go内存模型的文章有很多。

推荐先阅读的文章:


看完这些,我们首先看一些一般性的内存模型例子:

thread 1 thread 2
x = 1; while (done==0) {};
done = 1; print(x);

上面的代码结果是可以输出0吗?

测试的go代码:

下面贴出它在nanopi(linux arm)上的执行结果:

pi@nanopi:home/pi$ ./csub -run ./sub
detected 1 run times 2502
detected 2 run times 12099
detected 3 run times 20173
detected 4 run times 21717
detected 5 run times 24605
detected 6 run times 26428
detected 7 run times 27316
detected 8 run times 32485
detected 9 run times 36591
detected 10 run times 37471
detected 11 run times 40090
detected 12 run times 45609
detected 13 run times 54260
detected 14 run times 54378
detected 15 run times 55655
detected 16 run times 56905
detected 17 run times 58546
detected 18 run times 60083
detected 19 run times 60228
detected 20 run times 60790

相同的测试时长,mac上无任何输出

thread 1 thread 2
x = 1 y = 1
r1 = y r2 = x

上面代码是否会出现 r1 == r2 == 0呢?

下面来个图示:

eg

一份c++示例代码

此时再返回到go内存模型,这个时候就已经是语言层面提供的内存一致性保证了(由编译器保证),脱离了硬件层面的差异。总之,Don’t be clever,写代码老老实实把可能会并发读写的变量串行化访问就好了。

参考文章: