来自公众号:Gopher指北
文章目录
Go内存模型明确指出,一个goroutine如何才能观察到其他goroutine对同一变量的写操作。
当多个goroutine并发同时存取同一个数据时必须把并发的存取操作序列化。在Go中保证读写的序列化可以通过channel通信或者其他同步原语(例如sync包中的互斥锁、读写锁和sync/atomic中的原子操作)。
Happens Before
在单goroutine中,读取和写入的行为一定是和程序指定的执行顺序表现一致。换言之,编译器和处理器在不改变语言规范所定义的行为前提下才可以对单个goroutine中的指令进行重排序。
a := 1
b := 2
由于指令重排序,b := 2
可能先于a := 1
执行。单goroutine中,该执行顺序的调整并不会影响最终结果。但多个goroutine场景下可能就会出现问题。
var a, b int
// goroutine A
go func() {
a := 5
b := 1
}()
// goroutine B
go func() {
for b == 1 {
}
fmt.Println(a)
}()
执行上述代码时,预期goroutine B能够正常输出5,但因为指令重排序,b := 1
可能先于a := 5
执行,最终goroutine B可能输出0。
注:上述例子是个不正确的