c++ - 同时使用非原子和原子操作

标签 c++ c++11

我有一个线程池,每个线程都包含一个计数器(基本上是 TLS)。

主线程需要通过计算所有线程本地计数器的总和来频繁更新。

大多数时候,每个线程都会递增自己的计数器,因此不需要同步。

但是在主线程更新的时候,我当然需要某种同步。

我想出了 MSVS 内在函数(_InterlockedXXX 函数),它表现出了出色的性能(在我的测试中大约 0.8 秒) 但是,它将我的代码限制在 MSVC 编译器和 X86/AMD64 平台上,但是是否有一种 C++ 可移植的方法来做到这一点?

  • 我尝试将 int 类型更改为 std::atomic<int>对于柜台,使用 std::memory_order_relaxed对于增量,但这个解决方案非常慢! (~ 4 秒)

  • 使用基础成员时std::atomic<T>::_My_val ,该值是按我希望的那样以非原子方式访问的,但它也不可移植,所以问题是一样的......

  • 使用单个 std::atomic<int>由于竞争激烈(~ 10 秒),所有线程共享甚至更慢

你有什么想法吗?也许我应该使用图书馆(提升)?还是编写我自己的类?

最佳答案

std::atomic<int>::fetch_add(1, std::memory_order_relaxed)_InterlockedIncrement 一样快.

Visual Studio 将前者编译为 lock add $1 (或等同物),后者为 lock inc ,但执行时间没有区别;在我的系统(Core i5 @3.30 GHz)上,每个都需要 5630 ps/op,大约 18.5 个周期。

使用 Benchpress 的微基准测试:

#define BENCHPRESS_CONFIG_MAIN
#include "benchpress/benchpress.hpp"
#include <atomic>
#include <intrin.h>

std::atomic<long> counter;
void f1(std::atomic<long>& counter) { counter.fetch_add(1, std::memory_order_relaxed); }
void f2(std::atomic<long>& counter) { _InterlockedIncrement((long*)&counter); }
BENCHMARK("fetch_add_1", [](benchpress::context* ctx) {
    auto& c = counter; for (size_t i = 0; i < ctx->num_iterations(); ++i) { f1(c); }
})
BENCHMARK("intrin", [](benchpress::context* ctx) {
    auto& c = counter; for (size_t i = 0; i < ctx->num_iterations(); ++i) { f2(c); }
})

输出:

fetch_add_1                           200000000        5634 ps/op
intrin                                200000000        5637 ps/op

关于c++ - 同时使用非原子和原子操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36544855/

相关文章:

c++ - Clang 格式 AlignConsecutiveDeclarations 奇怪的行为

c++ - 如何从函数返回 vector 引用?

c++ - 使C++自动将int转换为double

c++ - 如何访问在结构/类范围内声明的别名?

c++ - 在基于范围的 for 循环中使用 shared_ptr 到 std::vector

c++ - super SDK : dependency errors

c++ - 如何解决错误提示 "No matching function call for XXX"?

c++ - 使特定于 Unix 的 CMake 过程跨平台

c++ - 仅 header 库中的静态 constexpr 成员初始化

c++ - 从排列的解析器表达式列表中动态(在运行时)生成 Spirit 解析器表达式