Go 1.6: fatal error: concurrent map read and map write

xuanbao · 2016-03-13 16:45:21 · 3571 次点击    
这是一个分享于 2016-03-13 16:45:21 的资源,其中的信息可能已经有所发展或是发生改变。

Hi all,

I have a wrapper struct around map to provide thread safety. See:

import "sync"
type struct MyMap {
    Data map[string]string
    sync.RWMutex
}
func (s *MyMap) Set(key string, value string) {
    s.Lock()
    s.Data[key] = value
    s.Unlock()
}
func (s *MyMap) Get(key string) string {
    s.RLock()
    defer s.RUnlock()
    return s.Data[key]
}

Nothing special, I bet most of you have this kind of data structure in your codebase.

In Go 1.6, s.RLock(); defer s.RUnlock() no longer protect me from race condition. What am I missing?

UPDATE: The answer is that I was sharing the map in All() method instead of copying.


评论:

allhatenocattle:

For this type of struct, why is the Data field being exported? It seems like you might be accidentally accessing Data directly somewhere without using Set/Get. I am also curious to see the actual error and source code that demonstrates the problem.

pinpinbo:

Sorry for the delayed response.

Great point, I'll change it to private and run -race again, see what I stumble next.

dgryski:

I agree that looks like it should work. Can you produce an entire program that demonstrates the issue? Is there a race somewhere else? What does the race detector say?

dgryski:

Also, please run go vet and make sure you're never passing a MyMap by value.

pinpinbo:

Sorry for the delayed response:

You can see the full library here: https://github.com/resourced/resourced/blob/master/libmap/libmap.go

I captured the -race stack trace here: https://gist.github.com/didip/bd8b49f6b18fa6ee4190

Nothing surprising, typical race problem: 1 thread tries to set() and the other one tries to get()

go vet does not return anything.

earthboundkid:

All returns the original map, not a copy, thereby bypassing all locks. You need to grab the lock and do a full copy instead.

pinpinbo:

Yup, this is the answer. I was sharing map instead of copying. Thanks!

danielt0shea:

Is it possible that you call NewTSafeMapCounter with an existing map parameter and the map is used by two go-routines?

pinpinbo:

Yup, this is the answer. I was sharing map instead of copying. Thanks!

danielt0shea:

If you run the race detector what does it say?


入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3571 次点击  
加入收藏 微博
0 回复
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传