C++并发编程之线程异步std::packaged_task知识点总结

1、std::packaged_task介绍

类模板 std::packaged_task 包装任何可调用 (Callable) 目标(函数、 lambda 表达式、 bind 表达式或其他函数对象),使得能异步调用它。其返回值或所抛异常被存储于能通过 std::future 对象访问的共享状态中。—摘抄自https://www.apiref.com/cpp-zh/cpp/thread/packaged_task.html

接下来看下std::packaged_task的定义:

  /// packaged_task
  template<typename _Res, typename... _ArgTypes>
    class packaged_task<_Res(_ArgTypes...)>
    {
      typedef __future_base::_Task_state_base<_Res(_ArgTypes...)> _State_type;
      shared_ptr<_State_type>                   _M_state;

    public:
      // Construction and destruction
      packaged_task() noexcept { }

      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 2095.  missing constructors needed for uses-allocator construction
      template<typename _Allocator>
	packaged_task(allocator_arg_t, const _Allocator& __a) noexcept
	{ }

      template<typename _Fn, typename = typename
	       __constrain_pkgdtask<packaged_task, _Fn>::__type>
	explicit
	packaged_task(_Fn&& __fn)
	: packaged_task(allocator_arg, std::allocator<int>(),
			std::forward<_Fn>(__fn))
	{ }

      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 2097.  packaged_task constructors should be constrained
      template<typename _Fn, typename _Alloc, typename = typename
	       __constrain_pkgdtask<packaged_task, _Fn>::__type>
	explicit
	packaged_task(allocator_arg_t, const _Alloc& __a, _Fn&& __fn)
	: _M_state(__create_task_state<_Res(_ArgTypes...)>(
		    std::forward<_Fn>(__fn), __a))
	{ }

      ~packaged_task()
      {
        if (static_cast<bool>(_M_state) && !_M_state.unique())
	  _M_state->_M_break_promise(std::move(_M_state->_M_result));
      }

      // No copy
      packaged_task(const packaged_task&) = delete;
      packaged_task& operator=(const packaged_task&) = delete;

      template<typename _Allocator>
	packaged_task(allocator_arg_t, const _Allocator&,
		      const packaged_task&) = delete;

      // Move support
      packaged_task(packaged_task&& __other) noexcept
      { this->swap(__other); }

      template<typename _Allocator>
	packaged_task(allocator_arg_t, const _Allocator&,
		      packaged_task&& __other) noexcept
	{ this->swap(__other); }

      packaged_task& operator=(packaged_task&& __other) noexcept
      {
	packaged_task(std::move(__other)).swap(*this);
	return *this;
      }

      void
      swap(packaged_task& __other) noexcept
      { _M_state.swap(__other._M_state); }

      bool
      valid() const noexcept
      { return static_cast<bool>(_M_state); }

      // Result retrieval
      future<_Res>
      get_future()
      { return future<_Res>(_M_state); }

      // Execution
      void
      operator()(_ArgTypes... __args)
      {
	__future_base::_State_base::_S_check(_M_state);
	_M_state->_M_run(std::forward<_ArgTypes>(__args)...);
      }

      void
      make_ready_at_thread_exit(_ArgTypes... __args)
      {
	__future_base::_State_base::_S_check(_M_state);
	_M_state->_M_run_delayed(std::forward<_ArgTypes>(__args)..., _M_state);
      }

      void
      reset()
      {
	__future_base::_State_base::_S_check(_M_state);
	packaged_task __tmp;
	__tmp._M_state = _M_state;
	_M_state = _M_state->_M_reset();
      }
    };

2、std::packaged_task重要的函数介绍

void swap(packaged_task& __other);//两个packaged task互换
bool valid();//如果有一个新的shared state就产生true。
// Result retrieval
future<_Res> get_future();//获得一个future 对象,可以用来取的shared state
// Execution
void operator()(_ArgTypes... __args);
void make_ready_at_thread_exit(_ArgTypes... __args);
//调用task并且在线成退出时使shared state为ready
void reset(); //建立一个新的shared state,会使shared state为ready
/// swap
template<typename _Res, typename... _ArgTypes>
    swap(packaged_task<_Res(_ArgTypes...)>& __x, packaged_task<_Res(_ArgTypes...)>& __y);

3、std::packaged_task用法示例

具体示例代码如下:

/*************************************************************************
	> File Name: thread_packaged_task.cpp
	> Author: 小和尚敲木鱼
	> Mail:  
	> Created Time: Tue 21 Sep 2021 02:40:24 AM PDT
 ************************************************************************/

#include <iostream>
#include <thread>
#include <string>
#include <vector>
#include <list>
#include <mutex>
#include <future>
#include <chrono>

using namespace std;
/*****************************文件说明***********************************/
int function_1(int param)//线程
{
	int ret = 10;
	std::cout << __func__ << "param =" << param  << std::endl;
	std::cout << "handle thread id ="<< std::this_thread::get_id() << std::endl;
	std::chrono::milliseconds sleep_time(500);
	std::this_thread::sleep_for(sleep_time);
	std::cout << __func__ << " thread id ="<< std::this_thread::get_id() << std::endl;
	std::cout << __func__ << " return = "<< ret + param << std::endl;
	return (ret + param);
}

int main(int agc,char * agv[])
{
	int temp = 20;
	std::cout << "Main thread id =" << std::this_thread::get_id() << std::endl;
	std::packaged_task<int(int)> handle_task(function_1);//创建packaged_task
	std::thread thread_test(std::ref(handle_task),temp);


	std::future<int> result = handle_task.get_future();
	std::cout << "###################" << std::endl;
	std::cout << "result = " << result.get() << std::endl;
	
	if (thread_test.joinable())
		thread_test.join();

	return 0;
}
//OUT
//Main thread id =140609886185280
//###################
//function_1param =20
//handle thread id =140609868805888
//function_1 thread id =140609868805888
//function_1 return = 30
//result = 30
/**************************end of file**********************************/

4、总结

std::packaged_task简单来说就是,打包一个异步任务去完成,完成打包后就不用管了,到合适的地点去获取相应的执行结果就可以了。非常的银杏。
Todo:
后续补充其他细节。

上一篇:【006】Email Future-给未来的自己写封信


下一篇:C++11 异步操作