首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么memory_order_relaxed性能与memory_order_seq_cst相同

为什么memory_order_relaxed性能与memory_order_seq_cst相同
EN

Stack Overflow用户
提问于 2018-12-17 02:15:14
回答 1查看 1.3K关注 0票数 8

我已经创建了一个简单的测试来检查std::memory_order_relaxed如何比atomic<int>增量的std::memory_order_seq_cst值更快。但是,这两种情况的性能是相同的。

我的编译器: gcc 7.3.0版(Ubuntu 7.3.0-27ubuntu1~18.04)

构建参数: g++ -m64 -O3 main.cpp -std=c++17 -lpthread

CPU:英特尔(R)酷睿(TM) i7-2670QM CPU @2.20 CPU,4核,每个核2个线程

测试代码:

代码语言:javascript
复制
#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总是产生几乎相同的结果?

结果:

rel: 2411时长: 4440ms

cst: 120000164时长: 4443ms

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-12-17 02:46:39

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

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

来自cppreference (我的斜体):

std::memory_order指定如何围绕原子操作对常规的非原子内存访问进行排序。

论文Memory Models for C/C++ Programmers在这方面提供了更多的细节。

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

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53805142

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档