2014-11-22 259 views
16

我試圖確定何時可以安全地撥打wait()std::futurestd::shared_future。我從來沒有撥打get()上的future,並且future已經準備好從對其承諾的相應承諾set_value()方法。在std :: future上多次調用wait()並從多個線程安全地調用?

我想等這個future(使用wait()wait_for()wait_until())從多個線程。在promise::set_value()已被呼叫立即返回之後,我也希望撥打wait()

http://www.cplusplus.com/reference/future/future/wait/

調用未來的對象是無效的,在這個成員函數產生不確定的行爲

獲取從promise一個futurevalid()==true開始其關閉。據我所見,只有future::get()valid()回到假。這個假設是否正確?我可以根據需要經常撥打wait()系列功能嗎?諾言的價值設定後,將立即撥打wait()立即返回?我可以從多個線程調用它們嗎?

回答

13

從一個承諾得到一個未來啓動它關閉有效()==真。據我可以看到只有future :: get()將valid()設置回false。這個假設是否正確?

它也可以通過移動分配一個無效的未來,或通過移動未來使其共享狀態轉移到不同的對象而變得無效。它不會因爲等待而失效。

我可以根據需要經常調用wait()系列函數嗎?

是的。

立即返回諾言的值後,將調用wait()嗎?

是(這可能涉及到鎖定一個互斥體或自旋鎖來檢查狀態準備好,然後返回,這樣可能涉及一個小型等待獲取鎖)

我可以給他們打電話從多個線程?

是的。

wait()是一個const成員函數,所以需要該庫確保可以從多個線程中的單個未來對象調用它,而無需用戶提供任何同步。

+1

我不確定簡單地做一個函數'const'保證它*線程安全*。規範提到這是一個要求嗎? – Galik 2014-11-22 14:51:30

+2

我不喜歡使用「線程安全」這個詞,因爲它對不同的人意味着不同的事情。 17.6.5.9 [res.on.data.races]表示標準庫必須確保在一個對象上調用(僅)'const'成員函數不會引入數據競爭。如果對象具有與其他對象共享的狀態(如'將來'那樣),則庫必須提供其自己的同步以防止競賽。這並不意味着簡單地添加'const'就是提供線程安全的magic pixie dust,這意味着庫有時需要做額外的工作來爲'const'函數提供保證。 – 2014-11-22 14:52:10

+0

簡單的事實,'wait()'是'const'只是保證函數不會修改對象的狀態。然而,它並不保證結果與其他線程所做的更改保持一致/同步。 – Christophe 2014-11-22 15:05:34

2

從多個線程訪問單個future可能會導致數據競爭和未定義的行爲,如果其中至少有一個可能執行get()並且沒有適當的同步可以避免這種情況。

因此,如果您需要從多個線程訪問future,你應該更好地考慮shared_future"They also allow the value in the shared state to be retrieved multiple times once ready."他們是線程安全的,只要每個線程訪問使用其自己的shared_future對象的共同未來。

注:我的回答假設在某個時刻一個get()會發生,因爲承諾沒有明確地提到的是promise<void>

+1

在多個線程中訪問結果衝突並可能導致數據競爭,但只是等待共享狀態變爲就緒狀態不會。 OP明確表示「我從未打電話過get()未來」,所以永遠不會訪問結果。 – 2014-11-22 14:34:10

+0

即使這個問題與這個問題無關,你的第二段可能會被誤解,意味着更多的「線程安全」比實際保證的更多。即使您通過不同的'shared_future'對象([futures.state] p11)訪問結果,對結果的訪問仍然存在衝突。 – 2014-11-22 14:47:16

+1

我同意簡單訪問wait()不是問題。問題在於訪問的繼承,因爲對一個特定未來實例的成員函數的調用不能保證同步(請參閱「C++併發實踐」,等待多個線程,第55頁)。 – Christophe 2014-11-22 14:57:22