使用std::async遇到的異常問題
1.crash 在std中 thread 和 condition_variable相關的地方
2.導致線程卡住
vs2013下使用沒問題,升級到vs2015後出現
#include "stdafx.h"
#include <stdarg.h>
#include <thread>
#include <future>
#include <iostream>
#include <windows.h>
using namespace std;
void connect()
{
std::async(std::launch::async, [](){
for (int i = 0; i < 5; ++i)
{
Sleep(1000);
cout << i << endl;
}
});
cout<< "finished connection" << endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
connect();
while (1){
cout << "main thread" << endl;
Sleep(500);
}
cout << "end connection" << endl;
return 0;
}
這樣的寫法在vs2013中沒有問題,但在 vs2015中就引發以上兩個問題,甚至間接的引發別的異常
在vs2015編譯器下,包括在gcc編譯器下,該異步方法會阻塞調用它的線程,直到子線程結束。而在vs2013的編譯器下,異步方法不會阻塞當前線程.
std::future<T>::~future
C++
Thread support library
std::future
~future();
(since C++11)
Releases any shared state. This means
if the return object or provider holds the last reference to its shared state, the shared state is destroyed; and
the return object or provider gives up its reference to its shared state; and
these actions will not block for the shared state to become ready, except that it may block if all of the following are true: the shared state was created by a call to std::async, the shared state is not yet ready, and this was the last reference to the shared state.
終於在官方文檔中http://en.cppreference.com/w/cpp/thread/future/~future找到了解釋,原文如上:
具體原因就是:
當以下三個條件全部滿足時,future的析構有可能會阻塞線程狀態變爲ready,也就是可能會阻塞線程:
1.共享狀態是通過std::async創建
2.共享狀態還不是ready狀態
3.被析構的future對象是共享狀態的最後一個引用
最後其實還是vs2013對C++11標準不完全支持
問題:
I updated my Visual Studio from 2013 to 2017. Compiling was fine but it seems like that the std::async call didn't open a new thread. (I cant see a new one in the thread-window while debugging. Also it looks like the thread which calls the the async function does the job...)
That is my function call:
std::async(std::launch::async, myfunction, this);
I didn't change anything in my code and in VS2013 was everything working fine.
Any Idea? Google can't tell me a lot about this but maybe i have the wrong keywords. So keywords would also help!
Thank you
回答1:
You need to hold on to the
std::future
returned byasync
otherwise the destructor of the temporary will block until the work is finished.auto t = std::async(std::launch::async, myfunction, this);
回答2:
In VS2013,
std::async
does not obey the C++ standard.There was a disagreement, and the developers working on MSVC wanted
std::async
'sstd::future
to behave like every otherstd::future
.The standard disagreed.
They released a non-standard compliant
std::future
in 2013. In 2015 if I remember correctly, they started following the standard.The standard states that the destructor of the
std::future
owning the shared state generated bystd::async( std::launch::async
blocks until the task is complete.This is because, in practice, dangling threads are bad for programs behaving in a predictable manner.
You are now in charge of owning and persisting the
future
returned fromauto f = std::async(std::launch::async, myfunction, this);
and
f.wait
orf.get
ing it when you need it to be ready.This may require changing how your code works; for example, keeping a vector of futures around (if you have more than one), or adding a
std::future<?>
member tothis
and storing it (this also ensures that the async call doesn't outlive the object lifetime!).As a second note,
std::async
on windows also uses a bounded thread pool; if there are more than a certain number ofasync
tasks active, new tasks may not be launched.They have plans to fix it (as it goes against the advice in the standard), but at this point I would still recommend using
std::thread
, and if you needstd::async
like behavior implementing something similar yourself.My personal tendency is to create problem-specific
thread_pool
s that own a certain number ofstd::thread
s, but let you queue tasks and getfuture
s (with custom extensions that give me very limited continuation capabilities) back from it.This makes the thread ownership and dependencies more explicit, and avoids dealing with the MSVC non-standard compliant quirks that still exist.
回答3:
Looks like std::async is whaiting for return to end. So, if you symply call it, doesn't work asynchronous.
std::async(std::launch::async, myfunction, this);
The Key is define an answer: myfunction must to return std::future and you need to define and same type to response.
std::future<int> foo = std::async(std::launch::async, myfunction, this);
In case you call std::async inside a constructor, foo must be member of the class.
class MyClass { //Your code private: std::future<int> exitThread; }
And, when you call std::async must be
exitThread = std::async(std::launch::async, myfunction, this);
回答4:
Very simple Solution:
std::thread t(myfunction, this); t.detach();
From VS2013 to VS2017 std::async does not start a new thread
Reference: