Go语言RWMutex仍触发竞态条件?问题排查求助
为什么你的Go代码会出现竞态条件?
嘿,这个问题其实挺常见的,我来帮你找出问题所在并修复它!
核心问题:返回了原始切片的引用
你的Ids结构体里的Read()方法犯了一个典型的错误——直接返回了受保护的切片i.e的引用。
Go里的切片是引用类型,它包含三个部分:指向底层数组的指针、长度和容量。当你执行return i.e时,你返回的是切片结构体的副本,但这个副本里的指针仍然指向和原切片相同的底层数组。这就意味着:
- 当读锁通过
defer i.RUnlock()释放后,其他goroutine可以通过Append()获取写锁并修改底层数组 - 而此时拿到
Read()返回值的代码可能还在访问这个底层数组,这就产生了竞态条件
修复方案:返回切片的拷贝
要解决这个问题,你需要在Read()方法里返回切片的独立拷贝,这样返回的切片会指向新的底层数组,和原切片的修改完全隔离。修改后的Read()方法如下:
func (i *Ids) Read() []int64 { i.RLock() defer i.RUnlock() // 通过append创建新切片,返回原始数据的拷贝 return append([]int64(nil), i.e...) }
额外的小问题:main函数里的goroutine未启动
看你的main函数,你定义了100个goroutine,但没有实际调用它们:
go func() { fmt.Printf("...") } // 这里缺少(),goroutine不会执行
应该改成:
go func() { fmt.Printf("...") }()
不过这只是示例的笔误,核心的竞态问题还是切片引用的问题。
验证修复效果
修复后,你可以用Go的竞态检测器来确认问题解决:
go run -race your_file.go
这时候应该不会再出现竞态条件的提示了。
内容的提问来源于stack exchange,提问作者stevenspiel
相关产品推荐
相关产品推荐

