go版本 devel +a714470 Wed Sep 27 16:29:18 2017 +0000 linux/amd64
以下程序报告了竞争,尽管对x的读取不能与对x的赋值并行进行,因为我们等待连接关闭后再读取它。
https://play.golang.org/p/ufvoScCbSm
==================
WARNING: DATA RACE
Read at 0x00c42008a220 by main goroutine:
main.main()
/home/rog/src/tst.go:24 +0x288
Previous write at 0x00c42008a220 by goroutine 7:
main.main.func1()
/home/rog/src/tst.go:16 +0x7a
Goroutine 7 (finished) created at:
main.main()
/home/rog/src/tst.go:14 +0x16d
==================
2017/10/04 16:48:53 1
Found 1 data race(s)
exit status 66
9条答案
按热度按时间vnzz0bqm1#
如果Dial和Read因为某种原因返回错误,那么在写入之前会有一个读取操作。
2q5ifsrm2#
这并不适用于Dial——如果Dial返回错误,我们会退出,但我添加了一些额外的错误检查以使代码更清晰。我修复了上面链接指向新代码的问题。
rfbsl7qr3#
我认为你可能对比赛检测器要求过高了。两个不同的网络连接之间没有明显的原因关联。我的意思是,当然有关联,但只有当你知道创建一个的
Dial
与创建另一个的Accept
相匹配时。只有当你知道这一点时,你才能看到一个的Close
影响另一个的Read
。CC @dvyukov
x6yk4ghg4#
@ianlancetaylor这是否适用于通过网络连接的任何因果关系(例如,使用httptest.Server并依赖于在HTTP请求回复后能够读取变量)?
3qpi33ja5#
据我所知,是的。
vaj7vani6#
有趣的是,这并不是我之前考虑过的事情。我怀疑我们有数百个可能带有种族标签的测试与此问题有关。
cnwbcb6i7#
我仍然看到两个不同的问题。
除非我对事物如何工作的理解不准确。
qni6mghb8#
由于
c.Close()
将调用内核,我认为任何合理的Go编译器都无法将x++
移动到调用之外。同样,我认为x++
必须被发布。我认为任何Go实现都必须假设内核可能会创建一个happens-before关系。这是事实,虽然这不在内存规范中,但总的来说,Go并不试图欺骗程序员。jljoyd4f9#
最终,任何系统调用都可以与任何其他系统调用同步(例如,创建一个文件,另一个进程注意到目录变得非空并向我们发送信号,因此现在文件的创建与信号的到来在某种程度上是同步的)。但是,将所有事物与所有事物同步会产生实质性的负面影响,即掩盖真正的数据竞争。
在C++中,我们进行更详细的逻辑处理,例如实际上跟踪由管道返回的一对fd之间的连接,然后如何通过dup传播:
http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_fd.cc?revision=308929&view=markup
但我们仍然不跟踪套接字之间的关系,理论上应该可以通过查看本地/对等地址来跟踪进程内的连接,但这仍然无法解决当连接经过单独的进程/机器时的问题。
总之:我不认为Go有简单的方法可以解决这个问题。如果我们谈论测试,我建议添加一个单独的通道,用于通知请求/连接处理完成。