您的位置:首页 > 编程语言 > C语言/C++

std::async在gcc和vc不同编译器下的不同表现(可能会阻塞)

2017-07-23 18:35 489 查看
最近由于项目的需要,在学习c++11中的std::async,想在项目中直接利用其异步操作的特性,而不是thread。但是该方法却在不同的编译器下有着不同的表现。

实验环境一:

操作系统:ubuntu 12.0.4 32位

编译器:gcc 5.4.1

源码:

#include <stdarg.h>
#include <thread>
#include <future>
#include <iostream>
#include <unistd.h>
using namespace std;

void connect()
{
std::async(std::launch::async, [](){
for (int i = 0; i < 5; ++i)
{
sleep(1);
cout << i << endl;
}
});
//f.wait();
cout<< "finished connection" << endl;
}
int main()
{
connect();
while (1){
cout << "main thread" << endl;
sleep(1);
}
cout << "end connection" << endl;
return 0;
}
运行结果:

0
1
2
3
4
finished connection
main thread
main thread
main thread
main thread
main thread
main thread
main thread
main thread
main thread
main thread


实验环境二:

操作系统:win7 32位

编译器:vs2013的编译器版本(至少vc10以上吧)

源码:

#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;
}
运行结果:

finished connection
main thread
main thread
0
main thread
main thread
1
main thread
main thread
2
main thread
main thread
3
main thread
main thread
4
main thread
main thread
main thread
main thread
main thread
main thread
main thread
main thread
从上面的运行差异看来,在gcc编译器下,该异步方法会阻塞调用它的线程,直到子线程结束。而在vs的编译器下,异步方法不会阻塞当前线程。至于具体原因,还有待进一步研究。。。。
8月1日

终于在官方文档中http://en.cppreference.com/w/cpp/thread/future/~future找到了解释,原文如下:


std::future::~future

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 tostd::async,
the shared state is not yet ready, and this was
the last reference to the shared state.

具体原因就是:

当以下三个条件全部满足时,future的析构有可能会阻塞线程状态变为ready,也就是可能会阻塞线程:

1.共享状态是通过std::async创建

2.共享状态还不是ready状态

3.被析构的future对象是共享状态的最后一个引用

根据以上结论,修改程序:

void connect()

{
std::future<void> f = std::async(std::launch::async, [](){
for (int i = 0; i < 5; ++i)
{
sleep(1);
cout << i << endl;
}
});
cout<< "finished connection" << endl;

}

运行结果为:

finished connection

01234

因为最后一个future引用f的作用域是整个函数,所以会阻塞在函数返回前。而实验1std::async创建的是一个future临时对象,该临时future对象的作用域只在当前语句,所以会阻塞在输出“0,1,2,3,4”,再输出“finished connection”。那么如何延长future的生命周期呢?其实我们可以返回该future对象。代码如下:

future<void> connect()

{
std::future<void> f = std::async(std::launch::async, [](){
for (int i = 0; i < 5; ++i)
{
sleep(1);
cout << i << endl;
}
});
cout<< "finished connection" << endl;
return f;

}

main.cpp

int main()

{
std::future<void> f = connect();
while (1){
cout << "main thread" << endl;
sleep(1);
}
cout << "end connection" << endl;
return 0;

}

这样connect就不会再阻塞了。
注意:

std::future 的拷贝构造函数是被禁用的,只提供了默认的构造函数和 move 构造函数(注:C++ 新特新)。另外,std::future 的普通赋值操作也被禁用,只提供了 move 赋值操作。如下代码所示:

 std::future<int> f, f1;            // 默认构造函数

 f = std::async(do_some_task);   // move-赋值操作

 f1 = f; // error

 f1 = std::move(f); //correct
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++ async vs2013 gcc