gpt4 book ai didi

c++ - 为什么 memory_order_relaxed 性能与 memory_order_seq_cst 相同

转载 作者:可可西里 更新时间:2023-11-01 18:35:22 33 4
gpt4 key购买 nike

我创建了一个简单的测试来检查 std::memory_order_relaxedstd::memory_order_seq_cstatomic<int> 的值增量。然而,这两种情况的性能是相同的。
我的编译器:gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)
构建参数:g++ -m64 -O3 main.cpp -std=c++17 -lpthread
CPU:Intel(R) Core(TM) i7-2670QM CPU @ 2.20GHz,4 核,每核 2 线程
测试代码:

#include <vector>
#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>
#include <functional>

std::atomic<int> cnt = {0};

void run_test_order_relaxed()
{
std::vector<std::thread> v;
for (int n = 0; n < 4; ++n) {
v.emplace_back([]() {
for (int n = 0; n < 30000000; ++n) {
cnt.fetch_add(1, std::memory_order_relaxed);
}
});
}
std::cout << "rel: " << cnt.load(std::memory_order_relaxed);
for (auto& t : v)
t.join();
}

void run_test_order_cst()
{
std::vector<std::thread> v;
for (int n = 0; n < 4; ++n) {
v.emplace_back([]() {
for (int n = 0; n < 30000000; ++n) {
cnt.fetch_add(1, std::memory_order_seq_cst);
}
});
}
std::cout << "cst: " << cnt.load(std::memory_order_seq_cst);
for (auto& t : v)
t.join();
}

void measure_duration(const std::function<void()>& func)
{
using namespace std::chrono;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
func();
high_resolution_clock::time_point t2 = high_resolution_clock::now();
auto duration = duration_cast<milliseconds>( t2 - t1 ).count();
std::cout << " duration: " << duration << "ms" << std::endl;
}

int main()
{
measure_duration(&run_test_order_relaxed);
measure_duration(&run_test_order_cst);
return 0;
}

为什么 std::memory_order_relaxedstd::memory_order_seq_cst总是产生几乎相同的结果?
结果:
相对:2411 持续时间:4440 毫秒
cst:120000164 持续时间:4443ms

最佳答案

无论内存顺序设置如何,您都需要在两个循环中进行原子操作。事实证明,对于在大多数情况下本质上是强有序的 x86 处理器,这导致对每个 fetch_add 使用相同的 asm 代码:​​lock xadd。 x86 处理器上的这种原子操作始终顺序一致,因此在指定宽松的内存顺序时这里没有优化机会。

使用宽松的内存顺序可以进一步优化周围的操作,但您的代码不会提供任何进一步的优化机会,因此发出的代码是相同的。请注意,使用弱排序处理器(例如 ARM)或在循环中进行更多数据操作(这可能提供更多重新排序机会)时,结果可能会有所不同。

来自 cppreference (我的斜体):

std::memory_order specifies how regular, non-atomic memory accesses are to be ordered around an atomic operation.

论文Memory Models for C/C++ Programmers对此提供了很多更多的细节。

作为旁注,重复运行原子基准测试或在不同的 x86 处理器(即使是同一制造商)上运行它们可能会导致截然不同的结果,因为线程可能不会平均分布在所有内核上,并且缓存延迟是受它是本地内核、同一芯片上的另一个内核还是另一个芯片上的影响。它还受到特定处理器处理潜在一致性冲突的方式的影响。此外,1、2 和 3 级缓存的行为不同,RAM 也是如此,因此数据集的总大小也有显着影响。参见 Evaluating the Cost of Atomic Operations onModern Architectures .

关于c++ - 为什么 memory_order_relaxed 性能与 memory_order_seq_cst 相同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53805142/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com