【golang/问题记录】goroutine之间数据竞争问题

说在前面

  • 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.Childnil
    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的值不确定,所以探讨这个问题没有意义。附上链接

猜你喜欢

转载自blog.csdn.net/qq_33446100/article/details/127865705
今日推荐