[go memory model]( https://go.dev/ref/mem) 中说:
> ...each read of a single-word-sized or sub-word-sized memory location must observe a value actually written to that location (perhaps by a concurrent executing goroutine) and not yet oferwritten.
这句话是否可以理解为读一个字长以下的数据, 总是会读到某一次写入的数据, 而不会读到某个中间状态?
如果上述理解是正确的, 那么对于下面的程序:
```go
package main
import (
"fmt"
"sync"
"time"
)
type A struct {
data string
}
func main() {
a := &A{data: "b"}
go func() {
for {
if a.data == "a" {
a = &A{data: "b"}
} else {
a = &A{data: "a"}
}
}
}()
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
for i := 0; i < 100000; i++ {
// 复制 a 的指针, aa 在接下来的使用中应该指向同一个 A
aa := a
if aa.data != "a" && aa.data != "b" {
panic(aa.data)
}
}
wg.Done()
}()
}
start := time.Now()
wg.Wait()
fmt.Println(time.Since(start))
}
```
由于指针 `*A` 是一个字长, 那么读取变量 a 总是会读到某一个 A 地址, 所以 panic 不会发生, 但实际上会出现:
```bash
panic:
goroutine 6 [running]:
main.main.func2()
/Users/a/test/test.go:44 +0xa0
created by main.main in goroutine 1
/Users/a/test/test.go:40 +0x44
exit status 2
```
这是为什么? |
|