[英]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)...);
謝謝
該代碼應用了兩個導致問題的規則:
std::make_tuple
與類型推斷一起使用,因此它試圖根據 arguments ( std:: tuple
std::tuple<std::atomic<double>, std::atomic<double>, std::atomic<double>>
), 從 arguments 復制std::atomic
是不可復制的至少有三種不同的方法可以解決這個問題:
如果您想要對原始std::atomic
的引用的tuple
,請使用std::tie
,例如std::tie(a1, a2, a3)
。 沒有從原子中讀取實際數據,因此您不會收到任何投訴,但tuple
現在將包含對可能不斷變化的std::atomic<double>
的引用。
如果你想要一個當前在原子中的值的tuple
(將以未指定的順序提取,因為 C++ 不保證 arguments 的評估順序,因此你不能保證任何特定的結果順序如果另一個thread 仍在修改它們),做以下兩件事之一,以便std::make_tuple
知道它正在復制實際的double
值,而不是原子本身:
從變量顯式加載: 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);
兩全其美; 每次加載都沒有浪費的工作,只有一個柵欄可以保證在之后讀取非原子時不會遺漏任何在這些加載之前寫入的內容。
顯式模板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.