2017-05-03 44 views
0

我在需要異步運行函數的應用程序中使用std::async,並且使用SendMessage函數使用SendMessage函數從工作線程與UI交談。下面是從MFC測試應用程序的提取物證明我在做什麼:在Visual Studio 2013和2015之間的std :: async中的不同行爲

LRESULT CStdAsyncProjDlg::OnUserPlusOne(WPARAM, LPARAM) 
{ 
    MessageBox("Message", "Hello World Again", MB_OK); 

    return 0; 
} 

// Function that contains the async work. 
void TestAsync(HWND hDlg) 
{ 
    // Send a message to the UI from this worker. The WM_USER + 1 message 
    // handler is CStdAsyncProjDlg::OnUserPlusOne 
    SendMessage(hDlg, WM_USER + 1, 0, 0); 
} 

// This event is fired when a button is pressed on the MFC dialog. 
void CStdAsyncProjDlg::OnBnClickedButton1() 
{ 
    MessageBox("Message", "Hello World", MB_OK); 
    std::async(std::launch::async, TestAsync, m_hWnd); 
} 

在Visual Studio 2013上面的代碼按預期工作。當我按下按鈕時,我會看到一個顯示「Hello World」的消息框,一旦我在該消息框上單擊確定,我就會看到另一個顯示「Hello World Again」的消息框。

我面臨的問題是,一旦我將上面的代碼遷移到Visual Studio 2015編譯器,應用程序掛起SendMessage函數調用後。

在線閱讀(回答this question)它提到了std::future塊的析構函數。我已經更改了Visual Studio 2015中的代碼以存儲從std::async返回的std::future,這似乎解決了問題(應用程序未掛起,並且我收到第二個消息框)。然而,看看std::future的代碼,我看不出在Visual Studio 2013和2015之間有什麼不同。所以我的問題是std::async會導致這種行爲的工作方式發生了什麼變化?

感謝

+1

我很確定這是2013年的一個bug,因爲'async'返回的將來的析構函數一直需要阻塞。 [這個問題](http://stackoverflow.com/questions/43600159/msvc-2013-stdasync-works-asynchronously-without-wait)表現出相同的行爲。 VS2013有很好的C++ 11支持。 VS2015更新3或2017更加合規。 – NathanOliver

+0

啊,'異步'的奇妙世界,阻止未來和魔術僵局......請嘗試[此演示文稿](https://www.youtube.com/watch?v=QIHy8pXbneI),大約42:30。 –

+1

不要嘗試從單獨的線程SendMessage(),它很可能會阻止。使用PostMessage() –

回答

4

MSVC有一個bug在2013年的std::async的返回std::future的析構函數必須阻塞;他們故意沒有阻止,因爲他們在委員會中爭論不同的標準。

他們MSVC 2015年

之前修復這個找回最舊的行爲的一種方式是寫一個線程池類,並且將作業提交給它;當它的所有線程都在工作並且提交了一個新工作時,它就會產生線程。在銷燬時,線程池類會清理它擁有的線程。然後使用它的作業提交機制而不是std::async

在任何情況下,請避免在MSVC上使用std::async,因爲它包含另一個標準違反(如果不是中斷)使用線程池的功能,該線程池受限於某個與硬件相關的常量;如果您有太多活動的std::async's,新的不會啓動。這違反了C++標準給出的建議和精神,但在技術上並不違反(因爲C++標準給非線程線程實現帶來了可笑的餘地)。它很容易導致很難追蹤只發生在應用程序擴展並在更多位置使用std::async時發生的錯誤。

也許這是固定在MSVC的一些反覆,但我看了上次報告的是,它仍然是在2015年

這是另一個原因寫自己的線程池的作業隊列。至少你可以控制語義,而不是獲取MSVC當前正在發佈的任何隨機破碎或半破碎的實現。

+0

謝謝你。幸運的是,我沒有太多活動的std :: async,並且我會盡量避免它們,因爲MSVC實現並不好。我有一個問題,請。如果我有自己的函數在內部調用std :: async並返回該結果(未來),那麼返回的將來將存儲在該函數的調用站點的變量中是否安全?或者我必須在函數內部設置未來的變量?謝謝 –

+0

@AliAlamiri是的,未來的狀態四處移動。把它們看作是'unique_ptr '的一個包裝。 – Yakk

相關問題