我正在阅读preshing的博客
Memory Reordering Caught in the Act,并通过他的
example code再现记忆重新排序
然后我想知道我是否可以通过Go再现内存重新排序,所以我写了示例代码,但Go中没有显示内存重新排序.
我正在写信分享一些发现.
你能否帮助解释为什么Go不能获得记忆重新排序?谢谢.
Go中的示例代码:
package main import ( "fmt" "math/rand" ) var x,y,r1,r2 int var detected = 0 func randWait() { for rand.Intn(8) != 0 { } } func main() { beginSig1 := make(chan bool,1) beginSig2 := make(chan bool,1) endSig1 := make(chan bool,1) endSig2 := make(chan bool,1) go func() { for { <-beginSig1 randWait() x = 1 r1 = y endSig1 <- true } }() go func() { for { <-beginSig2 randWait() y = 1 r2 = x endSig2 <- true } }() for i := 1; ; i = i + 1 { x = 0 y = 0 beginSig1 <- true beginSig2 <- true <-endSig1 <-endSig2 if r1 == 0 && r2 == 0 { detected = detected + 1 fmt.Println(detected,"reorders detected after ",i,"iterations") } } }
汇编代码(“ndisasm -b 32”)在C与Go之间显示不同
>来自C的汇编代码
00000CF0 C705520300000100 mov dword [0x352],0x1 //X=1 -0000 00000CFA 8B0550030000 mov eax,[0x350] 00000D00 89054E030000 mov [0x34e],eax //r1=Y
> Go的汇编代码
000013EA 48 dec eax 000013EB C70425787F170001 mov dword [0x177f78],0x1 //x=1 -000000 000013F6 48 dec eax 000013F7 8B1C25807F1700 mov ebx,[0x177f80] 000013FE 48 dec eax 000013FF 891C25687F1700 mov [0x177f68],ebx //r1=Y 00001406 48 dec eax
似乎Go在共享内存访问时使用dec eax,但是dec eax可以防止内存重新排序是没有意义的
> Intel® 64 and IA-32 Architectures Software Developer Manuals第3卷第8.2节显示了可能阻止记忆重新排序的情况,但不包括dec eax …
>我试图在C代码中添加dec eax作为共享内存访问的余量,而内存重新排序仍然存在.
到现在为止,我并不知道这个原因.请帮我,谢谢.
解决方法
我没有看到任何地方设置GOMAXPROC?如果你不叫它,你将只运行一个cpu,不会显示重新排序:
http://golang.org/pkg/runtime/#GOMAXPROCS
更新:在Go 1.5(发布2015/08/19)以后,您不再需要设置GOMAXPROCS – Go默认使用所有的cpu.