当操作写入单个常量值时,代码中存在竞争条件是否存在任何问题?例如,如果有一个并行循环填充了seen
另一个数组中的每个值的数组arr
(假设索引越界没有问题)。关键部分可能是以下代码:
//parallel body with index i
int val = arr[i];
seen[val] = true;
由于写入的唯一值是true
这是否意味着不需要互斥锁,并且可能会损害性能?即使线程互相踩踏,它们也只是用相同的值填充地址,对吗?
C++ 内存模型不会为您提供写入相同值的免费通行证。
如果两个线程在没有同步的情况下写入非原子对象,则这只是一个竞争条件。竞争条件意味着您的程序执行未定义的行为。程序执行过程中任何地方发生的未定义行为意味着程序的行为(无论是在未定义行为之前还是之后)都不受 C++ 标准的任何限制。
给定的编译器可以自由地提供更自由的内存模型。我不知道有任何这样做。
您必须了解的一件事是 C++ 不是汇编宏语言。它不必生成您脑海中想象的简单汇编程序。相反,C++ 试图让编译器更容易地生成汇编程序,这是一个非常不同的事情。
编译器可以并且确实确定“如果 X 发生,我们会得到未定义的行为;因此在生成代码时,我将围绕 X 不发生的事实进行优化”。在这种情况下,编译器可以prove具有定义行为的程序可能具有相同的val
在两个不同的同步线程中。
所有这些都可能在生成任何程序集之前很久就发生。
在汇编级别,某些硬件可能会通过对多字节值进行未对齐的分配来执行有趣的操作。当声称是单线程写入的指令在两个不同的内核中的相同字节上发生时,某些硬件可能(理论上;我在实践中不知道任何情况)引发陷阱。
这就是 C++ 中的 UB。一旦你有了 UB,你就必须在编译器接触到的地方审计你的程序生成的汇编代码。如果你使用 LTO,这意味着在你的整个程序中,至少在调用或与执行 UB 的代码交互的所有地方,都达到了一个不清楚的距离。
只需编写定义的行为即可。只有当这被证明是一个关键任务性能瓶颈时,您才应该花更多的精力来优化它(首先是更快的定义行为,只有当失败时您才考虑 UB)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)