为具有竞争条件的程序添加锁定可以解决竞争条件并使竞赛检测器保持安静。 Go的赛车探测器怎么能意识到锁?
有人指出“比赛探测器只能检测
考虑以下计划: 一个goroutine睡眠5秒,另一个睡眠10秒,在大多数情况下他们不会同时写package main
import (
"sync"
"time"
)
func main() {
var a int
var wg sync.WaitGroup
workers := 2
wg.Add(workers)
for i := 1; i <= workers; i++ {
go func(sleep int) {
time.Sleep(time.Duration(sleep) * time.Second)
a = 1
wg.Done()
}(i * 5)
}
wg.Wait()
}
a
,但是竞赛检测器每次都会打印竞赛条件警告。为什么呢?
答案 0 :(得分:4)
竞赛检测器不分析源代码,也不知道你在源代码中添加了锁。
竞赛检测器在运行时工作:
当设置
a
命令行标志时,编译器使用代码记录所有内存访问,该代码记录访问内存的时间和方式,而运行时库则监视对共享变量的不同步访问。
由于这种设计,比赛探测器只能检测如果和 实际发生时的竞争条件。因此,当您添加正确的锁定/同步时,不会发生竞争条件(如果条件不符合),因此不会打印警告。
有关详细信息,请参阅此博客文章:Introducing the Go Race Detector
这篇文章:Data Race Detector
编辑您的示例:
可能你的2个goroutine永远不会达到他们在相同的物理时间写共享变量a
的程度(因为代码运行得如此之快,而且睡眠时间相对较大),但它们会运行并发,在不同的goroutines中,没有显式同步(同步点可能是通道通信,互斥锁定/解锁等)。
竞争条件并不意味着同时访问共享变量 (其中一个必须是写入)。如果访问共享变量并发(来自多个goroutines),则无需同步即可满足竞争条件。这可以在运行时由竞争检测器检测到(由于仪表化的存储器访问代码)。
允许编译器生成的代码在多个goroutine中使用compose
变量的缓存实例,运行时只需要保证缓存的实例是&#34;刷新&# 34;或者在达到同步点时丢弃。有关详细信息,请参阅The Go Memory Model。
另请注意,time.Sleep()
并不保证执行将在指定的持续时间后继续执行,只会暂停执行至少指定的持续时间(因此执行可能会继续执行稍后时间):
睡眠暂停当前goroutine 至少持续时间d。
答案 1 :(得分:0)
数据竞争检测器不进行静态分析。它不知道你的锁。它是经验性的,只是注意当你用锁运行你的代码时,两个线程永远不会同时写入相同的值(或者一次写入,一次读取)。