最近在肝MIT的6.824,Lab2需要看这个官方文档
文档第一行就写明了 Version of May 31, 2014 ,好像很老了,但一直没更新应该就是没大的变化吧,读起来
Happens Befor原则
- 只有当不会改变goroutine中的行为时,编译器才会进行指令重排
- 由于指令重排,一个goroutine观察到的执行顺序可能与另一个goroutine感知到的不一样,比如一个goroutine执行a=1,b=2;但另一个goroutine可能先看到b的值发生变化
- 为了明确读和写的要求,我们定义了happensbefore,一个在Go程序中内存执行的顺序。如果e1发生在e2之前,那么我们说e2发生在e1之后。如果e1没有发生在e2之前,也没有发生在e2之后,我们说e1和e2同时发生。(原文在下面,我没懂绕这一圈干啥= =)
If event e1 happens before event e2, then we say that e2 happens after e1. Also, if e1 does not happen before e2 and does not happen after e2, then we say that e1 and e2 happen concurrently.
- 如果以下两项都成立,则允许对变量 v 的读取 r 观察到对 v 的写入 w:
- r does not happen before w.
- There is no other write w’ to v that happens after w but before r.
意思就是说,我读之前就写完了,然后也没别的操作,那我就能读到这个更改的操作了
- 如果保证对变量v的读取r,只读到w操作
- w happens before r.
- 任何其他对v的操作要么在w之前,要么在r之后
(这不是废话么)
这对条件比第一条要求高; 它要求没有其他写入与 w 或 r 同时发生。
在单个goroutine中,没有并发,所以问题不大。但多个goroutine去获取同一个共享内存的时候,他们必须用同步事件来建立happens-before环境,来确保读操作会读到写完的结果
对变量v的初始化为0操作类似于内存模型中的写操作
Synchronization 同步
如果包 p 导入包 q,则 q 的 init 函数的完成发生在任何 p 的开始之前。
main.main 函数的启动发生在所有 init 函数完成之后。
Goroutine creation
The go statement that starts a new goroutine happens before the goroutine’s execution begins.
不能保证 goroutine 的退出发生在程序中的任何事件之前。
如果一个 goroutine 的效果必须被另一个 goroutine 观察到,请使用同步机制,例如锁或通道通信来建立相对顺序。
通道通信是 goroutine 之间同步的主要方式。 特定通道上的每个发送都与来自该通道的相应接收匹配,通常在不同的 goroutine 中。
通道上的发送发生在来自该通道的相应接收完成之前。
不行了?看不下去了,太绕了,还是看Go的书籍吧,这写得好绕