![](/img/trans.png)
[英]Is calling wait() on a std::future multiple times and from multiple threads safe?
[英]Is there a safe way to call wait() on std::future?
C ++ 11標准說:
30.6.6類模板未來
(3)“調用除析構函數,移動賦值運算符以外的任何成員函數的效果,或對未定義的
valid() == false
的未來對象的valid() == false
。”
那么,這是否意味着以下代碼可能會遇到未定義的行為?
void wait_for_future(std::future<void> & f)
{
if (f.valid()) {
// what if another thread meanwhile calls get() on f (which invalidates f)?
f.wait();
}
else {
return;
}
}
Q1:這真的是一種可能的未定義行為嗎?
Q2:是否有任何符合標准的方法來避免可能的未定義行為?
請注意,該標准有一個有趣的注釋[也在30.6.6(3)]:
“[注意:鼓勵實現檢測此情況並拋出future_error類型的對象,其錯誤條件為
future_errc::no_state
endnote]”
Q3:如果我只依賴標准的音符並且只使用f.wait()
而不檢查f
的有效性,這樣可以嗎?
void wait_for_future(std::future<void> & f)
{
try {
f.wait();
}
catch (std::future_error const & err) {
return;
}
}
事實證明,我的例子的真正問題不是直接由於並行修改(從單個線程調用單個修改get
,另一個調用valid
wait
並且wait
哪個是安全的)。
真正的問題是std::future
對象的get
函數是從不同的線程訪問的,這不是預期的用例! std::future
對象只能在單個線程中使用!
涉及的唯一其他線程是設置共享狀態的線程:通過從傳遞給std::async
的函數返回或者在相關的std::promise
對象上調用set_value
等。
更多:甚至wait
來自另一個線程的std::future
對象不是預期的行為(由於與我的示例#1中的UB非常相同)。 我們將在這個用例中使用std::shared_future
,讓每個線程都擁有一個std::shared_future
對象的副本。 請注意,所有這些都不是通過同一個共享std::future
對象,而是通過單獨的(相關)的對象!
底線:這些對象不應在線程之間共享。 在每個線程中使用單獨的(相關的)對象。
正常的std::future
本身並不是線程安全的。 所以是的,它是UB,如果你調用從單個std::future
上的多個線程修改函數,因為你有潛在的競爭條件。 雖然,從多個線程調用wait
是可以的,因為它是const / non-modification。
但是,如果你真的需要從多個線程訪問std::future
的返回值,你可以先調用std::future::share
來獲得一個std::shared_future
,你可以將它復制到每個線程然后每個線程都可以調用get
。 請注意,每個線程都有自己的std::shared_future
對象非常重要。
你只需要檢查有效,如果你的未來可能是無效的,那么正常的用例( std::async
等)和正確的用法(例如:不是callig get
兩次)不是這種情況。
期貨允許您從一個線程存儲狀態並從另一個線程檢索它。 它們不提供任何進一步的線程安全性。
這真的是一種可能的未定義行為嗎?
如果你有兩個線程試圖在沒有同步的情況下獲得未來的狀態,是的。 我不知道為什么你會這樣做。
是否有任何符合標准的方法來避免可能的未定義行為?
只嘗試從一個線程獲取狀態; 或者,如果您確實需要在線程之間共享它,請使用互斥鎖或其他同步。
如果我只依靠標准的說明,那沒關系
如果您知道您需要支持的唯一實現遵循該建議,是的。 但是沒有必要。
並且只使用
f.wait()
而不檢查f
的有效性?
如果你沒有做任何多線程訪問未來的怪異惡作劇,那么你可以假設它是有效的,直到你檢索到狀態(或將其移動到另一個未來)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.