C++ 11 std::async 使用問題

使用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 by async 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's std::future to behave like every other std::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 by std::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 from

auto f = std::async(std::launch::async, myfunction, this); 

and f.wait or f.geting 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 to this 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 of async 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 need std::async like behavior implementing something similar yourself.

My personal tendency is to create problem-specific thread_pools that own a certain number of std::threads, but let you queue tasks and get futures (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:

std::async在gcc和vc不同編譯器下的不同表現(可能會阻塞)

c++11 std::async使用注意

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章