C++11 async、future、packaged_task、promise

一、async

std::future是一个类模板
std::async 是一个函数模板
作用:启动一个异步任务,启动起来之后返回一个std::future对象
什么是“启动一个异步任务‘?
自动创建一个线程并且开始执行对应的线程入口函数,它返回一个std::future对象,这个对象里面就包含线程入口函数所返回的接口(线程返回的结果),可以通过调用future对象的成员函数get函数来获取。

#include <iostream>
#include <thread>
#include <future>
#include <chrono>

int myThread() 
{
	std::cout << "myThread() start" << "\tthread ID ="
		<< std::this_thread::get_id() << std::endl;
	std::this_thread::sleep_for(std::chrono::seconds(5));
	std::cout << "end" << "\t thread ID" << std::this_thread::get_id() << std::endl;
	return 10;
}

int main()
{
	std::cout << "main" << "\tthread ID =" << std::this_thread::get_id() << std::endl;
	std::future<int> result = std::async(myThread);
	std::cout << "continue......" << std::endl;
	int def = 0;
	std::cout << "myThread =" << result.get() << std::endl; 
	//future在未获取到线程的返回值的时候,调用future函数的get()函数的时候,会阻塞在本行
	//直到future获取到线程的返回值的时候,get()函数才会返回结果,程序继续执行
	std::cout << "I love China" << std::endl;
	return 0;
}

future类的成员函数get()只有在future得到线程的返回值的时候,get()函数才会返回,否则则会阻塞在当前的位置上,并且注意,get()函数只能调用一次。
future类的成员函数wait()函数会阻塞当前的进程,直到future得到线程的返回值,有点类似于join();
对于async创建线程于thread相同,如果需要调用类的成员函数

std::future<int> result = std::async(&A::myThread,std::ref(myOBJ),temp);

第一个参数为函数的地址,第二个参数为类的对象,后面的就是函数的参数

1.1我们可以给async传递一个额外的参数,该参数的类型是std::launch类型,来进行不同的操作

std::launch是一个枚举
在这里插入图片描述

1.1.1std::launch::deferred:表示线程入口函数调用延迟到std::future的wait函数或者get函数被调用才会执行线程函数。

#include <iostream>
#include <thread>
#include <future>
#include <chrono>

class A
{
public:
	int myThread(int temp)
	{
		std::cout << "myThread() start" << "\tthread ID ="
			<< std::this_thread::get_id() << std::endl;
		std::cout << "temp = " << temp << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(5));
		std::cout << "end" << "\t thread ID" << std::this_thread::get_id() << std::endl;
		return 10;
	}
};

int main()
{
	A myOBJ;
	int temp = 12;
	std::cout << "main" << "\tthread ID =" << std::this_thread::get_id() << std::endl;
	std::future<int> result = std::async(std::launch::deferred,&A::myThread,std::ref(myOBJ),temp);
	std::cout << "continue......" << std::endl;
	std::cout << "I love China" << std::endl;
	return 0;
}

当给async加上额外的参数std::launch::defferred的时候在不调用wait或者get函数的时候,这个线程并不会被创建。
在这里插入图片描述
在调用wait函数的时候
在这里插入图片描述
我们可以发现子线程的ID竟然于主线程的ID相同,说明并没有子线程调用,说明延迟调用并没有创建新的线程,而是在主线程中进行的。

1.1.2std::launch::async,表示在调用async的时候就开始创建线程

std::future<int> result = std::async(std::launch::async,&A::myThread,std::ref(myOBJ),temp);

在这里插入图片描述
可以看到现在确实创建了一个新的线程。不需要调用wait或者get函数才创建线程。std::async函数的默认值就是std::launch::async。

二、std::packaged_task

是一个类模板,他的模板参数是各种可调用参数,通过std::packaged_ task来把各种可调用对象包装起来,方便将来作为线程入口

#include <iostream>
#include <thread>
#include <future>

	int myThread(int temp)
	{
		std::cout << "myThread() start" << "\tthread ID ="
			<< std::this_thread::get_id() << std::endl;
		std::cout << "temp = " << temp << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(5));
		std::cout << "end" << "\t thread ID = " << std::this_thread::get_id() << std::endl;
		return 10;
	}

	int main()
	{
		std::cout << "main" << "\tthread ID =" << std::this_thread::get_id() << std::endl;
		std::packaged_task<int(int)>myPT1(myThread);  //相当于myThread通过packaged_task包装
		std::thread myThread1(std::ref(myPT1), 1); //创建新的线程
		myThread1.join();
		std::future<int> result = myPT1.get_future();
		std::cout << "future = " << result.get() << std::endl;
		std::packaged_task<int(int)>myPT2([](int var) {
			std::cout << "var =" << var << std::endl;
			std::cout << "Thread() start" << "\tthread ID ="
				<< std::this_thread::get_id() << std::endl;
			return 5;
			});
		myPT2(100);  //相当于直接调用函数,并没有创建线程
		result = myPT2.get_future();
		std::cout << "future = " << result.get() << std::endl;
		return 0;
	}

在这里插入图片描述
可以看到通过thread创建了新的线程,直接调用就相当于调用函数,是在主线程中进行的。

		std::cout << "main" << "\tthread ID =" << std::this_thread::get_id() << std::endl;
		std::packaged_task<int(int)>myPT1(myThread); 
		std::vector<std::packaged_task<int(int)>> myPackVec;
		myPackVec.push_back(std::move(myPT1));
		auto iter = myPackVec.begin();
		std::packaged_task<int(int)>myPT2;
		myPT2 = std::move(*iter);
		myPackVec.erase(iter); //此时需要即使的删除,move并没有对容器本身操作,内部size任为1,但是包含的内容已经失效
		myPT2(15);
		std::future<int>result = myPT2.get_future();
		std::cout << "future =" << result.get() << std::endl;

通过容器对packaged_task进行操作时,需要使用std::move来进行操作。

三、std::promise

是一个类模板
作用:可以在某一个线程中给他赋值,然后我们可以再在其他线程中,把这个值取出来

#include <iostream>
#include <thread>
#include <future>
#include <chrono>

void myThread1(std::promise<int> &myProm, int calc)
{
    calc += 10;
    std::this_thread::sleep_for(std::chrono::seconds(2));
    myProm.set_value(calc);
    return;
}
void myThread2(std::future<int>& temp)
{
    std::cout << "temp.get() =" << temp.get() << std::endl;
    return;
}
int main()
{
    std::promise<int> myPromise;
    std::future<int> result = myPromise.get_future();
    std::thread t1(myThread1, std::ref(myPromise), 100);
    t1.join();
    std::thread t2(myThread2, std::ref(result));
    t2.join();
    std::cout << "main end" << std::endl;
    return 0;
}

  • 22
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值