具有相同值的并行写入
Parallel writes of a same value
我有一个程序,它产生了多个线程,这些线程可以将完全相同的值写入完全相同的内存位置:
std::vector<int> vec(32, 1); // Initialize vec with 32 times 1
std::vector<std::thread> threads;
for (int i = 0 ; i < 8 ; ++i) {
threads.emplace_back([&vec]() {
for (std::size_t j = 0 ; j < vec.size() ; ++j) {
vec[j] = 0;
}
});
}
for (auto& thrd: threads) {
thrd.join();
}
在这个简化的代码中,所有线程都可以尝试将完全相同的值写入vec
中的相同内存位置。这是一场可能触发未定义行为的数据竞赛吗?还是安全的,因为在所有线程再次连接之前,永远不会读取值?
如果存在潜在的危险数据竞争,使用std::vector<std::atomic<int>>
代替std::memory_order_relaxed
存储是否足以防止数据竞争?
语言律师回答,[interro.multithread]n3485
21程序的执行包含数据竞赛,如果它在不同的线程中包含两个冲突的操作,其中至少有一个不是原子的,也没有发生在另一个之前。任何此类数据竞赛都会导致未定义的行为。
4两个表达式求值冲突如果其中一个修改内存位置,另一个修改访问或修改相同的存储器位置。
将
std::vector<std::atomic<int>>
与std::memory_order_relaxed
存储一起使用是否足以防止数据竞争?
是的。这些访问是原子访问,在通过线程连接引入关系之前,会发生。从生成这些工作线程(通过.join
同步)的线程中进行的任何后续读取都是安全和定义的。
这是一场数据竞赛,编译器最终会变得足够聪明,如果他们还没有对代码进行错误编译的话。请参阅第2.4节"如何对具有"良性"数据竞争的程序进行错误编译",了解相同值的写入会破坏代码的原因。
实现细节答案:
虽然语言标准将其归类为未定义的行为,但只要你真的在写相同的数据,你就可以感到非常安全。
为什么?硬件将对同一存储单元的访问顺序化。唯一可能出错的是同时写入多个存储单元,因为硬件无法保证对多个单元的访问以相同的方式顺序化。例如,如果一个进程写入0x0000000000000000
,而另一个进程则写入0xffffffffffffffff
,则硬件可能会决定以不同的方式对不同字节的访问进行顺序化,从而产生类似0x00000000ffffffff
的结果。
然而,如果两个进程写入的数据相同,那么两种可能的序列化之间没有明显的差异,结果是确定的。
现代硬件不以逐字节的方式处理内存访问,相反,CPU通过缓存线与主内存通信,内核通常可以通过8字节字与缓存通信。因此,设置一个正确对齐的指针是一个原子操作,可以依靠它来实现无锁定算法。在更强大的原子操作可用之前,Linux内核就已经利用了这一点。C++将其形式化为atomic<>
类型,增加了对更高级硬件功能的支持,如读后写、原子增量等。
但是,当然,如果你依赖你的硬件细节,你真的应该在做之前知道你在做什么。否则,坚持使用atomic<>
类型等语言功能,以确保正确的操作并避免UB。
@落选者:
问题是而不是标记的[语言律师],答案明确表示"实现细节答案"。这是有意解释UB在节目中会是什么样子在现实生活中。写这个答案是为了用不同的观点来补充公认的答案(我投了赞成票)。
- C++17中的并行执行策略
- 并行用于C++17中数组索引范围内的循环
- 如何在Elixir中调用递归函数并行
- OpenMP:并行更新数组总是需要减少数组吗
- 如何使用OpenMP并行这两个循环
- 如何使用OpenMP并行化此矩阵时间矢量运算
- 如何使用OpenMP使这个循环并行
- 遍历并行数组以确定C++中的最大数字
- 为什么 openmp 的并行不适用于矢量化色彩空间转换?
- 如何在 Mac 上使用 c++17 并行标准库算法?
- 并行标准::复制复杂性
- 如何使用 MPI 的远程内存访问 (RMA) 功能并行化数据聚合?
- 在C++中使用并行化的预期速度是多少(不是 OpenMp,而是 <thread>)
- 如何在 C++17 STL 并行算法中处理调度?
- OpenMP 与有序和关键指令并行
- OpenMP for 循环并行性问题
- 两个连续的 OpenMP 并行区域会相互减慢速度
- C++17:如何在并行 STL 中获取工作项的索引
- 如何使用 OpenMP 并行化最近邻搜索
- 如何使用 winsock2 实现与 c++ 的多个并行连接?