<p>Hi all,</p> <p>I have a wrapper struct around map to provide thread safety. See:</p> <pre><code>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] } </code></pre> <p>Nothing special, I bet most of you have this kind of data structure in your codebase.</p> <p>In Go 1.6, <code>s.RLock(); defer s.RUnlock()</code> no longer protect me from race condition. What am I missing?</p> <p><strong>UPDATE:</strong> The answer is that I was sharing the map in <code>All()</code> method instead of copying.</p> <hr/>**评论:**<br/><br/>allhatenocattle: <pre><p>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. </p></pre>pinpinbo: <pre><p>Sorry for the delayed response.</p> <p>Great point, I'll change it to private and run <code>-race</code> again, see what I stumble next.</p></pre>dgryski: <pre><p>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?</p></pre>dgryski: <pre><p>Also, please run go vet and make sure you're never passing a MyMap by value. </p></pre>pinpinbo: <pre><p>Sorry for the delayed response:</p> <p>You can see the full library here: <a href="https://github.com/resourced/resourced/blob/master/libmap/libmap.go" rel="nofollow">https://github.com/resourced/resourced/blob/master/libmap/libmap.go</a></p> <p>I captured the <code>-race</code> stack trace here: <a href="https://gist.github.com/didip/bd8b49f6b18fa6ee4190" rel="nofollow">https://gist.github.com/didip/bd8b49f6b18fa6ee4190</a></p> <p>Nothing surprising, typical race problem: 1 thread tries to set() and the other one tries to get()</p> <p><code>go vet</code> does not return anything.</p></pre>earthboundkid: <pre><p><code>All</code> returns the original map, not a copy, thereby bypassing all locks. You need to grab the lock and do a full copy instead. </p></pre>pinpinbo: <pre><p>Yup, this is the answer. I was sharing map instead of copying. Thanks!</p></pre>danielt0shea: <pre><p>Is it possible that you call NewTSafeMapCounter with an existing map parameter and the map is used by two go-routines?</p></pre>pinpinbo: <pre><p>Yup, this is the answer. I was sharing map instead of copying. Thanks!</p></pre>danielt0shea: <pre><p>If you run the race detector what does it say?</p></pre>
