std::async在gcc和vc不同编译器下的不同表现(可能会阻塞)
2017-07-23 18:35
489 查看
最近由于项目的需要,在学习c++11中的std::async,想在项目中直接利用其异步操作的特性,而不是thread。但是该方法却在不同的编译器下有着不同的表现。
实验环境一:
操作系统:ubuntu 12.0.4 32位
编译器:gcc 5.4.1
源码:
实验环境二:
操作系统:win7 32位
编译器:vs2013的编译器版本(至少vc10以上吧)
源码:
8月1日
终于在官方文档中http://en.cppreference.com/w/cpp/thread/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
实验环境一:
操作系统: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
相关文章推荐
- 发现VC编译器和gcc编译器的一点不同
- 栈变量被覆盖的问题在不同编译器中的表现,蛋疼的VC++
- gcc编译与vc编译器区别
- getline 在不同编译器的表现,对换行符的处理
- 自增运算符在gcc和vc下的不同结果
- (转)gcc编译与vc编译器区别
- 在vc下和gcc下不同函数名,可使用宏来判断处理
- 【转】不同的编译器:GCC G++ C C++的区别
- VC与DEV编译器关于ifstream的文本反复读取问题存在的不同
- 不同的编译器:GCC G++ C C++的区别
- 不同的编译器:GCC G++ C C++的区别
- 【转】gcc和vc编译器在语法上的比较
- [C] 让VC支持C99的整数类型V1.01。避免包含目录问题,更名auto_stdint.h、auto_inttypes.h(在VC6至VC2012、GCC、BCB等编译器下测试通过)
- gcc和vc编译器在语法上的比较
- [C] 让VC支持C99的整数类型V1.01。避免包含目录问题,更名auto_stdint.h、auto_inttypes.h(在VC6至VC2012、GCC、BCB等编译器下测试通过)
- GCC 和 VC 关于函数提前申明的不同要求。
- gcc与g++在对待const _实参传给_形参的不同表现
- GCC 和 VC 关于函数提前申明的不同要求。
- C++构造函数、拷贝构造函数、赋值运算符重载 调用时机 GCC与VC在对象作为返回值的不同处理
- gcc和vc编译器区别