C++内存模型——这个例子包含数据竞赛吗
C++ memory model - does this example contain a data race?
我正在阅读Bjarne Stroustrup的C++11常见问题解答,我很难理解内存模型部分的一个例子。
他给出了以下代码片段:
// start with x==0 and y==0
if (x) y = 1; // thread 1
if (y) x = 1; // thread 2
常见问题解答说这里有而不是数据竞赛。我不明白。内存位置x
由线程1读取,并由线程2写入,而不进行任何同步(y
也是如此)。这是两次访问,其中一次是写入。这不是数据竞赛的定义吗?
此外,它还说"(据我所知)每一个当前的C++编译器都给出了一个正确的答案。"这个正确的答案是什么?答案难道不会因为一个线程的比较发生在另一个线程写入之前还是之后而有所不同吗?
// start with x==0 and y==0
if (x) y = 1; // thread 1
if (y) x = 1; // thread 2
由于x和y都不是真的,所以另一个也不会设置为真。无论指令的执行顺序如何,(正确的)结果始终是x保持0,y保持0。
内存位置
x
是。。。由线程2 写入
真的吗?你为什么这么说?
如果y
为0,则x
不是由线程2写入的。并且CCD_ 6从0开始。类似地,除非y
在线程1运行之前是非零的,否则x
不可能是非零,而这是不可能发生的。这里的要点是,不执行的条件写入不会导致数据竞争。
不过,这是内存模型的一个不平凡的事实,因为不知道线程的编译器将被允许(假设y
不是易失性的)将代码if (x) y = 1;
转换为int tmp = y; y = 1; if (!x) y = tmp;
。然后将是一场数据竞赛。我无法想象它为什么要进行这种精确的转换,但这并不重要,关键是非线程环境的优化器可以做一些违反线程内存模型的事情。因此,当Stroustrup说他所知道的每个编译器都给出了正确的答案(也就是说,就在C++11的线程模型下)时,这是一个关于这些编译器为C++11线程化做好准备的重要声明。
CCD_ 12的一个更现实的变换将是CCD_。我认为,在您的示例中,这个将导致数据争用,并且在分配y = y
的标准中没有特殊处理,因此可以安全地执行相对于另一个线程中的y
的读取未排序的操作。你可能会发现很难想象它在硬件上不起作用,无论如何,我可能错了,这就是为什么我使用了上面的另一个例子,这个例子不太现实,但有明显的数据竞争。
必须有一个写入的总顺序,因为在其他线程首次将1
写入任一变量之前,没有线程可以写入变量x
或y
。换句话说,你基本上有三种不同的场景:
- 线程1可以写入
y
,因为x
是在if
语句之前的某个前一点写入的,然后如果线程2稍后到来,它会向x
写入与1
相同的值,并且不会更改其先前的1
值 - 线程2可以写入
x
,因为y
在if
语句之前的某个时间点发生了更改,然后线程1
将写入y
(如果稍后1
的值相同) - 如果只有两个线程,那么
if
语句将被跳过,因为x
和y
保持为0
这两次写入都没有发生,因此没有竞争。x和y都保持为零。
(这是关于虚幻写入的问题。假设一个线程在检查条件之前进行了推测性的写入,然后试图在检查条件之后进行更正。这会破坏另一个线程,所以这是不允许的。)
内存模型设置了代码和数据区域的可支持大小。在比较链接源代码之前,我们需要指定内存模型,即他可以设置数据和代码的大小限制。
- pcap_handler回调仅在使用 NPCAP v0.9991 时包含空数据包
- 如何避免在数据结构中包含存储为字段的类?
- C++ 打印包含数据结构的数组
- 读取大文件(>2GB)(文本文件包含以太网数据)并通过不同参数随机访问数据的最佳方法是什么?
- 派生的 wxPanel 控件如何访问其中包含 wxDialog 中的数据?
- 将包含二进制数据的 QByteArray 传递到按值运行
- 如果变量数据包含大于 vector 所有元素的整数,则仅在视觉工作室上接收"矢量下标超出范围"?
- 使用 range-v3 读取包含逗号分隔数据的行
- 即使类不包含数据,C++ 14 是否仍会生成默认函数?
- 指针数据类型变量如何包含对象?
- ctypes - 结构包含垃圾/不正确的数据
- 在wxWidgets的事件中包含我自己的数据的最佳方法是什么?
- C++ 矢量不显示包含对象的数据
- 拒绝包含某些公共静态数据成员的类型
- 在C++中设置仅包含每个类的一个外观的数据结构
- C++ 逐行从文件(包含空格)读取数据
- Python API用于解析包含数组格式的protobuf数据的二进制文件
- C++ 包含针对多种类型数据的布尔测试的模板会获得匹配错误
- 当数据包含空格时,如何将制表符分隔文件的内容加载到C++字符串的 2D 向量中
- 如何将 qrc 数据包含在使用 CMake 编译的基于 Qt 的二进制文件中