duankousong9637 2016-11-25 16:07
浏览 40
已采纳

从两个互斥体报告的数据竞争

An interesting issue has arisen today where I have code that contains more than one Mutex, each covering locking for distinct Maps.

Here is a similar in struct of my source code that I am using:

type MyStruct struct {
    dogMutex sync.RWMutex
    dogMap   map[int]Dog // keyed by PID
    catMutex sync.RWMutex
    catMap   map[int]Cat // keyed by (localAddress + localPort)
}

A more detailed example of the issue is here: https://play.golang.org/p/eic8q2VrNq

After building the executable with 'go build -race ..." the generated executable reports the following race

As the code is way more complex than the example above, it is interesting to notice that the data race is reported on the areas indicated in the code.

The following stack is from the real application.

1) The write operation reported on wwww.go:95 is equivalent to my WRITE comment in the code (MethodOne)

2) The previous read operattion reported on wwww.go:218 is equivalent to my READ comment in the code (MethodTwo)

=================
WARNING: DATA RACE
Write at 0x00c420017890 by goroutine 97:
  runtime.mapassign1()
      /usr/local/go/src/runtime/hashmap.go:442 +0x0
  main.(*NetworkManager).MethodOne()
      /opt/doppler/src/xxx/yyy/wwww.go:95 +0x745

Previous read at 0x00c420017890 by goroutine 70:
  runtime.mapiterinit()
      /usr/local/go/src/runtime/hashmap.go:620 +0x0
  main.NetworkManager.MethodTwo()
      /opt/xxx/src/xxx/yyy/wwww.go:218 +0x1e9
  main.(*NetworkManager).SomethingELse()
      /opt/xxx/src/xxx/yyy/wwww.go:174 +0x99d
  main.(*NetworkManager).SomethingFurther()
      /opt/xxx/src/xxx/yyy/wwww.go:102 +0x3c

I am wondering if this is a proper way of using mutexes. My code has much concurrency, but I am focusing this question on the fact that the race detector is reporting based on Apples vs Bananas (two completely distinct mutexes)

  • 写回答

1条回答 默认 最新

  • dongzhouzhang8696 2016-11-27 12:41
    关注

    Just going to take a guess, but one common cause of this issue is accidentally passing the struct which contains the pointers by value instead of by reference. For example:

    type MyStruct struct {
        dogMutex sync.RWMutex
        dogMap   map[int]Dog // keyed by PID
        catMutex sync.RWMutex
        catMap   map[int]Cat // keyed by (localAddress + localPort)
    }
    
    func (s MyStruct) Example() {
        // this lock doesn't actually work, but the map access does because its a 
        // reference type
        s.catMutex.Lock()
        s.catMap[1] = Cat{}
        s.catMutex.Unlock()
    }
    

    Another possibility is that perhaps you are passing the maps into your init:

    func (s *MyStruct) Init(cats map[int]Cat) {
        s.catMap = cats
    }
    

    And then you are modifying the map somewhere outside of the struct. If that's the case you need to create a new map and copy all the values.

    Incidentally go vet can detect many of these issues, try running it on your code: https://golang.org/cmd/vet/. (Also worth a try is the metalinter)

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 关于#MATLAB#的问题,如何解决?(相关搜索:信噪比,系统容量)
  • ¥500 52810做蓝牙接受端
  • ¥15 基于PLC的三轴机械手程序
  • ¥15 多址通信方式的抗噪声性能和系统容量对比
  • ¥15 winform的chart曲线生成时有凸起
  • ¥15 msix packaging tool打包问题
  • ¥15 finalshell节点的搭建代码和那个端口代码教程
  • ¥15 Centos / PETSc / PETGEM
  • ¥15 centos7.9 IPv6端口telnet和端口监控问题
  • ¥20 完全没有学习过GAN,看了CSDN的一篇文章,里面有代码但是完全不知道如何操作