Debugging Golang与地图上的sync.Mutex[字符串]int进行比赛
我有一个简单的软件包,用来记录程序运行期间的统计数据,我发现Debugging Golang与地图上的sync.Mutex[字符串]int进行比赛,debugging,go,race-condition,Debugging,Go,Race Condition,我有一个简单的软件包,用来记录程序运行期间的统计数据,我发现go run-race说其中有一个竞赛条件。看着这个程序,我不确定当每次读写都受到互斥保护时,我怎么会有竞争条件。有人能解释一下吗 package counters import "sync" type single struct { mu sync.Mutex values map[string]int64 } // Global counters object var counters = single
go run-race
说其中有一个竞赛条件。看着这个程序,我不确定当每次读写都受到互斥保护时,我怎么会有竞争条件。有人能解释一下吗
package counters
import "sync"
type single struct {
mu sync.Mutex
values map[string]int64
}
// Global counters object
var counters = single{
values: make(map[string]int64),
}
// Get the value of the given counter
func Get(key string) int64 {
counters.mu.Lock()
defer counters.mu.Unlock()
return counters.values[key]
}
// Incr the value of the given counter name
func Incr(key string) int64 {
counters.mu.Lock()
defer counters.mu.Unlock()
counters.values[key]++ // Race condition
return counters.values[key]
}
// All the counters
func All() map[string]int64 {
counters.mu.Lock()
defer counters.mu.Unlock()
return counters.values // running during write above
}
我使用的软件包如下所示:
counters.Incr("foo")
counters.Get("foo")
在这里,一个最小的完整的可验证示例会很有用,但我认为您的问题在于
All()
:
这将返回一个
映射
,该映射不复制它,因此可以在互斥锁的保护之外访问它。All
返回基础映射并释放锁,因此使用映射的代码将有数据竞争
您应该返回地图的副本:
func All() map[string]int64 {
counters.mu.Lock()
defer counters.mu.Unlock()
m := make(map[string]int64)
for k, v := range counters.values {
m[k] = v
}
return m
}
或者没有All
方法
func All() map[string]int64 {
counters.mu.Lock()
defer counters.mu.Unlock()
m := make(map[string]int64)
for k, v := range counters.values {
m[k] = v
}
return m
}