(假设:
int x{ 6 }
和2个评价同时写x = 6
)
--
CPP 参考文献介绍了多线程执行和数据竞争 |数据竞赛:
当表达式的计算写入到内存位置并且 另一个评估读取或修改相同的内存位置, 据说表达式是冲突的。一个程序有两个冲突 评估存在数据竞争,除非:
两个评估都在同一线程或同一信号中执行 处理程序,或
两个相互冲突的评估都是原子操作(参见 std::atomic),或
其中一个相互矛盾的评估发生在 另一个(参见 std::memory_order)。
如果发生数据竞争,程序的行为是不确定的。
参考文献说:“另一个评估修改”;它没有说“另一个评价写”。
--
C++ 标准关于 6.9.2.2 数据竞争的规定:
- 两个表达式求值冲突,如果 其中一个 修改 内存位置 ([intro.memory]) 且 另一个 读取 或 修改相同的内存位置。
--
将相同的值重新写入内存位置是否算作修改内存?
向内存位置写入相同的值算作修改内存吗?
是的,例如,对标量对象的简单赋值(这就是内存位置实际上是什么,位字段除外)被定义为修改对象,无论对象要更改为什么值。请参阅 [expr.ass]/2:
- 在简单赋值 (=) 中,左操作数引用的对象通过将其值替换为右操作数的结果而被修改 ([defns.access])。
您会发现影响标量对象值的所有其他表达式都有类似的措辞。
关于术语,标准通常不使用“write”,而是使用“modify”,含义相同。参见例如[defns.access].
简短的回答是,修改意味着发生对对象的任何写访问。 即使这不会改变内存中的任何位,它也会修改抽象 C++ 意义上的值。
通过在抽象 C++ 意义上修改内存,您可能会遇到数据竞争,即使此修改不会更改内存中的任何位。
要获得更清晰的了解,请参阅 C++11 标准,[intro.multithread] p21:
注意:我引用 C++11 因为这是一个 c++11 问题。
conflict如果两个表达式求值之一修改 ([intro.memory]) 内存位置,而另一个表达式求值访问或修改同一内存位置,则两个表达式求值会发生冲突。如果程序在不同线程中包含两个冲突的操作,则该程序的执行包含“数据争用”,并且至少其中一个不是原子的,并且两者都不会在另一个之前发生。任何此类数据竞争都会导致未定义的行为。
相关的写法是
[intro.defs] 编辑 3470不幸的是,这就是事情变得不清楚的地方,因为“修改”实际上并没有在标准中定义;它没有在
在许多地方澄清了访问的含义。 access 表示读取或修改值。 冲突的当前定义也使用这种“读取或修改”术语,在[intro.races](工作草案)中。 标准中使用“访问”和“读取或修改”的方式通常不需要在修改之前/之后比较不相等的值。
如果通过错误的类型修改某些内容,即使内存中没有任何位发生更改,也违反了严格别名,并且
=
) 中,通过用右操作数的结果替换其值来修改左操作数引用的对象 ([defns.access])。
不要求新值与旧值比较不相等。对象总是会被修改。
您可以更改位,而不会发生任何可观察到的值变化
0 == 0; // guaranteed true, because zero compares equal to zero
int x = 0;
x = 0; // if int is padded, then this might modify padding bits of int
// even though the values compare equal before and after, bits are changed
您可以更改值而不更改任何存储位
通常指对象的状态。两个值是不同的,即使它们比较相等:
int x; // x has no value, but all of the bits in the storage could be zero here
std::construct_at(&x); // x now has value zero, and while this does change its value
// (it was indeterminate before), it might not have any affect
// on the bits of its storage
如您所见,更改内存中的位与修改值是不同的概念。 赋值总是
改变值。