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

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

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)

图片转代码服务由CSDN问答提供 功能建议

今天出现了一个有趣的问题,其中我的代码包含多个互斥对象,每个互斥对象涵盖了针对不同Map的锁定。

这是我正在使用的源代码的结构类似

  type MyStruct结构 {
 dogMutex sync.RWMutex 
 dogMap map [int] Dog //由PID键
 catMutex sync.RWMutex 
 catMap map [int] Cat //由(localAddress + localPort)键
} 
   
 
 

更详细的示例在这里: https://play.golang.org/p/eic8q2VrNq

使用“ go build -race ...”构建可执行文件后,生成的可执行文件将报告以下竞赛

由于代码比上面的示例复杂得多,因此有趣的是注意到数据竞争是在代码中指示的区域上报告的。

以下堆栈来自真实的应用程序。

1)在wwww.go:95上报告的 write 操作等效于我在代码(MethodOne)中的WRITE注释

2)在wwww.go:218上报告的先前的阅读操作等同于我在代码(MethodTwo)中的READ注释

  = 警告:DATA RACE 
通过goroutine 97在0x00c420017890处写入:
 runtime.mapassign1()
 / usr / local / go / src / runtime / hashmap  .go:442 + 0x0 
 main。(* NetworkManager).MethodOne()
 /opt/doppler/src/xxx/yyy/wwww.go:95 + 0x745 
 
以前通过goroutine 70在0x00c420017890处读取:\  n 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()\  n /opt/xxx/src/xxx/yyy/wwww.go:102 + 0x3c 
   
 
 

我想知道这是否是使用静音的正确方法 XES。 我的代码具有很多并发性,但我将这个问题集中在以下事实上:种族检测器报告基于Apple vs Bananas(两个完全不同的互斥体)

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • dongzhouzhang8696
    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)

    点赞 评论

相关推荐