繁体   English   中英

无法从 C++ 中的原子 object 构造元组

[英]Cannot construct tuple from atomic object in C++

我是 C++ 中的原子新手,正在尝试从原子对象创建元组。 我收到编译时错误,我不明白为什么。 我该如何解决错误?

创建了这个测试程序

int main()
{
    std::atomic<double> a1{0};
    std::atomic<double> a2{0};
    std::atomic<double> a3{0};

    // Parallel processing
    ParallelFor(...) {
       // update atomic variables.
    }
    std::make_tuple(a1,a2,a3);
    return 0;
}

编译时错误:

In instantiation of 'constexpr std::tuple<typename std::__decay_and_strip<_Elements>::__type ...> std::make_tuple(_Elements&& ...) [with _Elements = {std::atomic<double>&, std::atomic<double>&, std::atomic<double>&}]':
progatomic.cpp:17:26:   required from here
error: no matching function for call to 'std::tuple<std::atomic<double>, std::atomic<double>, std::atomic<double> >::tuple(std::atomic<double>&, std::atomic<double>&, std::atomic<double>&)'
       return __result_type(std::forward<_Elements>(__args)...);

谢谢

该代码应用了两个导致问题的规则:

  1. 类型推断:您将std::make_tuple与类型推断一起使用,因此它试图根据 arguments ( std:: tuple std::tuple<std::atomic<double>, std::atomic<double>, std::atomic<double>> ), 从 arguments 复制
  2. 不可复制类型: std::atomic是不可复制的

至少有三种不同的方法可以解决这个问题:

  1. 如果您想要对原始std::atomic引用tuple ,请使用std::tie ,例如std::tie(a1, a2, a3) 没有从原子中读取实际数据,因此您不会收到任何投诉,但tuple现在将包含对可能不断变化的std::atomic<double>的引用。

  2. 如果你想要一个当前在原子中的tuple (将以未指定的顺序提取,因为 C++ 不保证 arguments 的评估顺序,因此你不能保证任何特定的结果顺序如果另一个thread 仍在修改它们),做以下两件事之一,以便std::make_tuple知道它正在复制实际的double值,而不是原子本身:

    1. 从变量显式加载: std::make_tuple(a1.load(), a2.load(), a3.load()) 为了提高效率,由于顺序一致性实际上不能保证 arguments 的加载顺序,您可能希望明确放宽 memory 的排序要求,使用std::make_tuple(a1.load(std::memory_order_acquire), a2.load(std::memory_order_acquire), a3.load(std::memory_order_acquire)) ,甚至是std::memory_order_relaxed 从技术上讲,如果值是在没有std::memory_order_release或更强的情况下store的,则下降到acquire可能会让你看到非原子的不一致 state ,但如果这是一个问题,你可以使用:

       std::make_tuple(a1.load(std::memory_order_relaxed), a2.load(std::memory_order_relaxed), a3.load(std::memory_order_relaxed)); std::atomic_thread_fence(std::memory_order_seq_cst);

      两全其美; 每次加载都没有浪费的工作,只有一个栅栏可以保证在之后读取非原子时不会遗漏任何在这些加载之前写入的内容。

    2. 显式模板make_tuple因此它隐式转换为基础值类型,而不是推断std::atomic<double>std::make_tuple<double, double, double>(a1, a2, a3) (缺点:由于现在load隐含的,你不能放松 memory 排序;三个 memory 栅栏将被涉及)

    这两种方法解决了上面的两个问题之一,要么通过显式模板(保留隐式加载)删除类型推断,要么通过转换为可复制类型的显式加载(保留隐式模板)删除复制。 任何一个(或两个)都可以解决问题,因为只有在涉及类型推断不可复制类型时才会出现问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM