说在前面
- go版本:go1.18.4 windows/amd64
测试代码
- 开三个
goroutine
,一个不断赋值,一个隔一段时间将其置空,一个判断是否为空之后进行一些操作type MainStruct struct { Child *ChildStruct } type ChildStruct struct { Value int } func TestMain() { tmp := &MainStruct{ Child: &ChildStruct{ Value: 0, }, } // 不断赋值 go func() { for { tmp = &MainStruct{ Child: &ChildStruct{ Value: 0, }, } } }() // 判空后进行一些操作 go func() { for { if tmp.Child != nil { tmp.Child.Value = 0 tmp.Child.Value++ } } }() // 不断置空 go func() { for { tmp.Child = nil } }() for { time.Sleep(time.Second * 10) } }
- 上述代码在执行一段时间后直接panic,原因是
tmp.Child
为nil
panic: runtime error: invalid memory address or nil pointer dereference [signal 0xc0000005 code=0x1 addr=0x0 pc=0xa8a0bc] goroutine 36 [running]: main.TestMain.func2() D:/gamemanager/src/go/test.go:393 +0x1c created by main.TestMain D:/gamemanager/src/go/test.go:389 +0xf6 exit status 2
- 但是当把判空并进行操作的那个
goroutine
代码改一下后,就没有panic过了go func() { for { if tmp.Child != nil { // tmp.Child.Value = 0 tmp.Child.Value++ } } }()
- 对于在
if
这个判定中访问tmp.Child
会出问题,我是明确的,因为这个时候tmp.Child
的值是不确定的,但是问题是为什么在去掉一行之后却没有问题。
尝试
- 去stackoverflow上问了下,大佬们说因为data race的存在,
tmp.Child
的值不确定,所以探讨这个问题没有意义。附上链接