簡體   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