You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

已加锁的Go代码为何仍被go run -race检测出DATA RACE?

Go Map并发竞态问题排查

我觉得下面的代码不该出现数据竞态,但日志里明确报了DATA RACE,试了用defer解锁也没解决,到底哪里漏了?

代码片段(some_file.go)

type Key struct {
}
type Val struct {
}

type Tmp struct {
    smMap map[Key]Val
    lock sync.RWMutex
}

func (t *Tmp) setMap(k Key, v Val) {
    t.lock.Lock()
    t.smMap[k] = v // line#13
    t.lock.Unlock()
}

func (t *Tmp) deleteFromMap(k Key) {
    t.lock.Lock()
    delete(t.smMap, k) // line#19
    t.lock.Unlock()
}

func (t *Tmp) getMap(k Key) Val {
    t.lock.Lock()
    defer t.lock.Unlock()
    return t.smMap[k]
}

竞态检测日志

WARNING: DATA RACE
Write at 0x00c0004cc990 by main goroutine:
runtime.mapassign()
/usr/local/go/src/runtime/map.go:578 +0x0
some_file.go:13 +0x70

Previous write at 0x00c0004cc990 by goroutine 925:
runtime.mapdelete()
/usr/local/go/src/runtime/map.go:695 +0x0
some_file.go:19

Goroutine 925 (running) created at:


问题排查方向

  • 存在未通过方法直接操作smMap的代码
    如果你在业务逻辑的其他地方,没有调用setMap/deleteFromMap/getMap,而是直接对smMap执行读写(比如tmp.smMap[key] = val或delete(tmp.smMap, key)),这类操作不会持有锁,必然引发竞态。

  • Tmp结构体被意外复制
    sync.RWMutex是值类型,绝对不能复制。如果代码中出现值传递Tmp实例的场景(比如把Tmp作为参数传给函数、赋值给其他变量),锁会被复制成多个独立实例,无法起到跨goroutine的互斥作用,等于没锁保护map的并发读写。

  • 锁的作用范围未覆盖完整操作
    检查setMap/deleteFromMap方法中,锁是否包裹了所有对smMap的操作。你当前的代码看起来没问题,但如果后续修改时在锁外新增了对smMap的操作,也会触发竞态。

另外补充:getMap是读操作,应该使用t.lock.RLock()和t.lock.RUnlock()(配合defer),这样允许多个读操作同时进行,提升并发性能,但这不是当前竞态的触发原因。


内容的提问来源于stack exchange,提问作者nimpostor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 04:30:26