C++11 多线程之 packaged_task

packaged_task是什么?

template< class R, class ...Args > 
class packaged_task< fn(Args...)>;

packaged_task是类模板,定义于future头文件中,它包装任何种类可调用的 目标(函数、lambda表达式、std::bind表达式或其他函数对象)。
异步调用后,返回值或所抛异常被存储在一个能通过std::future对象访问的共享状态中。
最简单的理解
将一个普通的函数对象转换为异步执行的任务

  1. 可调用实体(函数、lambda表达式、std::bind表达式或其他函数对象)
  2. 一个共享状态,通过关联的回调来存储返回的值或抛出的异常。

在packaged_task成员中,进行了()运算符重载,因此我们可以直接调用这个开始启动任务。

代码示例
#include 
#include 
#include 
using namespace std;
int TestFunc(int a, int b){
	cout << "thread id=" << std::this_thread::get_id() << " " << __FUNCTION__ << endl;
	int result = 0;
	for (int i = a; i < b; i++) {
		result += 3;
		std::this_thread::sleep_for(std::chrono::milliseconds(100));
	}
	return result;
}

void task_func()
{
	cout << "thread id=" << std::this_thread::get_id() << " " << __FUNCTION__ << endl;
	//包装普通函数
	std::packaged_task<int(int, int)> task(TestFunc);
	//std::packaged_task         task(std::bind(TestFunc, 33, 66));
	future<int>result = task.get_future();
	//启动任务,同步执行
	task(33, 66);
	//task();
	cout << "task_func TestFunc(33, 66) :" << result.get() << " " << __FUNCTION__ << endl;
}

void task_thread() 
{
	cout << "thread id=" << std::this_thread::get_id() << " " << __FUNCTION__ << endl;
	//构造时传递用于异步执行的函数指针add
	packaged_task<int(int, int)> ansyc_task(TestFunc);
	//从packaged_task<>获取相关的future
	future<int> future = ansyc_task.get_future();
	//创建线程,同时传递函数TestAdd的运行参数
	thread exec_thread(move(ansyc_task), 33, 66);
	//获得函数packaged_task在另一个线程中的运行结果
	int ret = future.get();
	//join线程,阻塞直到线程完成时返回
	exec_thread.join();
	cout << "TestFunc(1,20)=" << ret << " " << __FUNCTION__ << endl;
}
void task_lambda()
{
	cout << "thread id=" << std::this_thread::get_id() << " " << __FUNCTION__ << endl;
	//包装目标为lambda
	packaged_task<int(int, int)> task([](int a, int b) { return a + b; });
	//仿函数形式,启动任务
	task(33, 66);
	future<int> result = task.get_future();
	cout << "task_lambda (33, 66) :" << result.get() << " " << __FUNCTION__ << endl;
}

int main()
{
	task_func();
	task_lambda();
	task_thread();
	return 0;
}

执行结果:
C++11 多线程之 packaged_task_第1张图片

关键点:

packaged_task不可以复制,只可以移动,所以我们需要在将它移动到执行线程之前,从它那里获取 std::future对象。

类方法:
packaged_task.swap(packaged_task_other)
packaged_task.valid()          // 检查std::packaged_task是否拥有一个有效的函数
packaged_task.get_future()     // 获得与其封装的函数相绑定的future
packaged_task.make_ready_at_thread_exit(ex) // 执行相应的函数,其结果在线程退出时写到数据管道
packaged.reset()      // 重置task的状态,并废弃以前执行的结果
std::swap(packaged_task_1, packaged_task_2)   // 交换底层的task

你可能感兴趣的:(C++,C++,多线程,c++)