- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我创建了一个简单的测试来检查 std::memory_order_relaxed
比 std::memory_order_seq_cst
快atomic<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_relaxed
和 std::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/
给定: std::atomic x; uint64_t f() { x.store(20, std::memory_order::memory_order_relaxed); x.st
在 ThreadMethodOne 中加载时放宽变量 valA 和 valB 同步的最正确方法是什么(假设不存在 valA 和 valB 的虚假高速缓存行共享)?似乎我不应该将 ThreadMetho
假设线程 1 正在对变量 v 进行原子存储使用 memory_order_release (或任何其他顺序)并且线程 2 正在对 v 执行原子读取使用 memory_order_relaxed . 在
Stackoverflow 上已经有一些问题本质上是关于 memory_order_relaxed 的用例,例如: Understanding memory_order_relaxed What ar
C++ 内存模型放宽了原子性,不对内存操作提供任何顺序保证。除了我在这里找到的 C 中的邮箱示例: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1
Cppreference 给出 following example关于memory_order_relaxed: Atomic operations tagged memory_order_relax
读取 atomic_uint 的值有什么区别?使用 memory_order_relaxed,并读取 volatile unsigned int 的值(假设 volatile 操作是原子的)? 具体来
我试图了解 memory_order_relaxed 的细节。我指的是这个链接:CPP Reference . #include #include std::atomic ptr {nullptr
考虑以下摘自 Herb Sutter 关于原子的演讲的代码片段: smart_ptr 类包含一个名为 control_block_ptr 的 pimpl 对象,其中包含引用计数 refs。 // Th
我在看 this article来自 GCC Wiki 关于 C++ 内存屏障(及其很棒的)。 在我到达这一点之前,它非常简单: 相反的方法是 std::memory_order_relaxed。该模
据我所知,memory_order_relaxed 是为了避免昂贵的内存栅栏,这可能需要在特定架构上进行更多约束排序。在那种情况下,如何在流行的处理器上实现原子变量的总修改顺序? 编辑: atomic
下面是否保证打印 1 后跟 2? auto&& atomic = std::atomic{0}; std::atomic* pointer = nullptr; // thread 1 auto&&
我有一个写入原子变量的线程。 (使用 memory_order_release)。 线程 A 还有许多其他线程读取该变量。 (使用 memory_order_acquire)。 线程 B。 在线程 A
关于内存顺序的 cppreference 文档说 Typical use for relaxed memory ordering is incrementing counters, such as t
我正在研究这个网站:https://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync ,这对理解关于原子类的话题非常有帮助。 但是这个放松模式的例子很难理解:
假设我有一个线程 A 写入 atomic_int x = 0;,使用 x.store(1, std::memory_order_relaxed);。如果没有任何其他同步方法,使用 x.load(std
在以下代码中使用 std::memory_order_relaxed 是否正确? #include #include #include #include using namespace std
我正在研究 C++ 内存序列,但它很困惑。 例如: void sumUp(std::atomic& sum, std::vector& val) { int tmpSum = 0; for
C++ 标准规定,原子上的 RMW(读-修改-写)操作将对原子变量的最新值进行操作。因此,当从多个线程并发执行时,对这些操作使用 memory_order_relaxed 不会影响 RMW 操作。 我
std::atomic cnt = {2}; thread 1: doFoo(); if (cnt.fetch_sub(1, std::memory_order_relaxed) ==
我是一名优秀的程序员,十分优秀!