9.2. Happens Before
在一个单独的goroutine中,变量的读和写操作顺序和代码所写的顺序一致。因此,在变量值没有 被改变的时候, 编译器和处理器可能会记录变量的操作顺序。但是,这种先验性的顺序记录会导致 在两个不同的goroutine对变量操作 顺序记录有差别。例如,一个goroutine执行 a = 1; b = 2; , 但是在另一个goroutine中可能会现感知到b被更新。
为了解决这种二义性问题,Go语言中引进一个happens before的概念,它用于描述 对内存操作的先后顺序问题。如果 事件 e1 happens before 事件 e2,我们说 事件 e2 happens after e1。 如果, 事件e1 does not happen before 事件 e2,并且 does not happen after e2,我们说 事件e1和 e2同时发生
。
对于一个单一的goroutine,happens before 的顺序和代码的顺序是一致的。
如果能满足以下的条件,一个对变量v的读事件r可以 感知到另一个对变量v的写事件w:
- 写事件w happens before 读事件r。
- 没有既满足 happens after w 同时满主 happens before r的对变量v的写事件w。
为了保证读事件r可以感知对变量v的写事件,我们首先要 确保w是变量v的唯一的写事件。同时还要满足以下条件:
- 写事件w happens before 读事件r。
- 其他对变量v的访问必须 happens before 写事件w 或者 happens after 读事件r。
第二组条件比第一组条件更加严格。因为,它要求在w和 r并行执行的程序中不能再有其他的读操作。
对于在单一的goroutine中两组条件是等价的,读事件可以确保感知到对变量的写事件。但是,对于在 两个goroutines共享变量v,我们必须通过同步事件来保证 happens-before 条件 (这是读事件感知写事件的必要条件)。
将变量v自动初始化为零也是属于这个内存操作模型。
读写超过一个机器字长度的数据,顺序也是不能保证的。