2014-10-09 31 views
9

我正在學習C++中的互斥鎖,並且在下面的代碼中有問題(取自N. Josuttis的「The C++ Standard Library」)。C++程序意外地阻塞/拋出

我不明白爲什麼它塊/拋出除非我在主線程中添加this_thread::sleep_for(那麼它不會阻止所有三個電話都進行)。

編譯器是從命令行使用的cl.exe。

#include <future> 
#include <mutex> 
#include <iostream> 
#include <string> 
#include <thread> 
#include <chrono> 

std::mutex printMutex; 

void print(const std::string& s) 
{ 
    std::lock_guard<std::mutex> lg(printMutex); 

    for (char c : s) 
    { 
     std::cout.put(c); 
    } 
    std::cout << std::endl; 
} 

int main() 
{ 
    auto f1 = std::async(std::launch::async, print, "Hello from thread 1"); 
    auto f2 = std::async(std::launch::async, print, "Hello from thread 2"); 

    // std::this_thread::sleep_for(std::chrono::seconds(1)); 

    print(std::string("Hello from main"));  
} 
+3

您並未等待線程完成。我認爲這是MSVC庫的問題。 – Niall 2014-10-09 12:49:43

回答

11

我認爲你所看到的是與async(結合future)的MSVC實現的一致性問題。我相信這是not conformant。我能用VS2013重現它,但無法用gcc重現問題。

崩潰是因爲主線程在其他兩個線程完成之前退出(並開始清理)。

因此,兩個期貨的簡單延遲(sleep_for)或.get().wait()應該爲您解決它。所以修改後的main可能看起來像;

int main() 
{ 
    auto f1 = std::async(std::launch::async, print, "Hello from thread 1"); 
    auto f2 = std::async(std::launch::async, print, "Hello from thread 2"); 

    print(std::string("Hello from main"));  

    f1.get(); 
    f2.get(); 
} 

青睞明確的等待或克服定時「睡眠」。

注意事項一致性

有從Herb Sutter提案以改變從async返回的future的共享狀態中的等待或塊。這可能是MSVC行爲的原因,它可能被視爲已經實施了該提案。我不確定提案的最終結果是什麼或者它的整合(或其中的一部分)到C++ 14中。至少w.r.t.從async返回的future的阻塞看起來像MSVC行爲沒有將其納入規範。

有趣的是,請注意第30.6節中的措詞。8/5改變;

從C++ 11

共享該共享狀態創建 通過此async呼叫應,直到關聯的線程塊的異步返回對象到一個等待功能的呼叫已經完成,如果加入作爲

要C++ 14

共享噸異步返回對象到等待函數的調用他共享狀態下創建 本async通話將被阻塞,直到相關的線程已經完成,彷彿加盟,要不然時間 出

我不知道怎麼了「超時」將被指定,我會想象它是實現定義的。

+0

那麼預期的行爲是什麼?在沒有引用它們的情況下運行的線程(可能在主線程終止後)應該保持運行,類似於頭部被切斷的火雞 – Mikhail 2014-10-16 08:09:51

+0

@Mikhail。我喜歡火雞比喻,哈哈。我認爲這就是爲什麼提案可能被拒絕(至少是線程從任何等待狀態解除關聯的部分)。我認爲從'async'返回的'future'阻止是一個更好的主意。我也認爲,圍繞「未來」的來源有時會產生困惑,並且它是否會阻止 - 也許一個「async_future」可能是一個更好的主意,但我不知道。我認爲「異步」是一個很晚的補充,所以他們可能沒有解決所有更微妙的問題。 – Niall 2014-10-16 08:32:16

1

std::async返回future。它如果getwaitdestructor塊沒有被調用:

如果所有以下爲真它可能會阻止:共享狀態是通過調用創建到std ::異步,共享狀態還沒有準備好,這是共享狀態的最後一個參考。

請參閱std::futures from std::async aren't special!瞭解該主題的詳細處理。

+2

那麼它如何解釋崩潰? – 2014-10-09 12:59:43

+2

這是如何解釋說,如果他睡一秒鐘就可以工作? – 2014-10-09 13:01:35

1

main末添加這兩條線:

f1.wait(); 
f2.wait(); 

這將確保線程main存在之前完成。