```go
package main
import (
"fmt"
"time"
)
func main() {
var num = 10
var p = &num
c := make(chan int)
go func() {
time.Sleep(time.Second)
c <- *p //-----> 11
//c <- num //----->10
}()
time.Sleep(2 * time.Second)
num++
fmt.Println(<-c)
fmt.Println(p)
return
}
```
为什么 *p 和num的结果不一样
规范里面对Send statements的说明是:
Both the channel and the value expression are evaluated before communication begins
问题的关键在于communication begins发生在什么时候?
这里有4个时间点:
A:num++
B1:<-c begin
B2: <-c return
C1: c <- *p begin
C2: c <- *p return
D: *p这个表达式求值
根据Go memory model,有几个happen before是可以确定的:
C1在B2之前,B2在C2之前, A在B1之前,B1在B2之前
C1--------B2-----C2
|
A---B1----
communication begins的时间点应该是B1与B2之间,并且同时也是C1与C2之间,按上图就是:max(B1, C1)到B2之间的一个时间点,假设为X
就是说D发生在goroutine里面time.Sleep(time.Second)之后,X之前
那么就有下面两种情况:
如果B1>C1(C1发生在B1之前),那么X在B1与B2之间,A一定在X之前,但是D也在X之前,A和D的顺序不能确定
如果C1>B1(B1发生在C1之前),那么X在C1与B2之间,A一定在X之前,但是D也在X之前,A和D的顺序不能确定
#26
更多评论