Go中的内存可见性与happens-before
什么是内存模型 Go的内存模型特指在并发的场景下,一个goroutine所写的变量在另一个goroutine能在哪些情况下被观察到 在计算中,内存模型描述了多线程如何通过内存的交互来共享数据 官方建议 程序可能会并发地访问/修改一些变量,多个goroutine的并发访问一定要保证“可串行化”,尤其是绝对不允许出现数据竞争的场景下 为了保证数据访问的串行化访问,没有数据竞争,在Go语言中,尽量通过channel或者各种同步原语对数据的并发访问进行保护,例如sync 、sync/atomic等 强烈推荐阅读官方文档 If you must read the rest of this document to understand the behavior of your program, you are being too clever. Don’t be clever. C语言中的内存可见性 内存可见性是一个通用性质的问题,类似于 c/c++,golang,java 都存在相应的策略。作为比较,我们先思考下 c 语言,在 c 里面却几乎没有 happens-before 的理论规则,究其原因还是由于 c 太底层了,常见 c 的内存可见性一般用两个比较原始的手段来保证: volatile 关键字(很多语言都有这个关键字,但是含义大相径庭,这里只讨论 c ) memory barrier volatile volatile 声明的变量不会被编译器优化掉,在访问的时候能确保从内存获取,否则很有可能变量的读写都暂时只在寄存器。但是,c 里面的 volatile 关键字并不能确保严格的 happens-before 关系,也不能阻止 cpu 指令的乱序执行,且 volatile 也不能保证原子操作。 以一个常见的c代码为例: // done 为全局变量 int done = 0; while ( ! done ) { /* 循环内容 */ } // done 的值,会在另一个线程里会修改成 1; 这段代码,编译器根据自己的优化理解,可能在编译期间直接展开翻译成(或者每次都直接取寄存器里的值,寄存器里永远存的是 0 ): ...