(36)练习使用函 async (),这是一个简单的还算全面的举例:
++ 再举例:
++ 以上使用 auto 的原因是,我们知道 全局 async (…)函数会返回 future 对象,但也许无法确定 模板参数 T 的类型,所以留给编译器进行编译过程中的类型推断。
(37) 用 async (…)就不需要用 join ( ) 了,因为使用 async () 创建新线程任务,新线程任务是作为模板类 _Task_async_state 的数据成员,是会随着类对象的析构,而回收资源的。而且也不是对 thread 类的包装。 async ()技术使用了新的线程对象 _Task 。代码支持如下:
(38) 接着学习另一个重要的模板类 packaged_task<_Ret(_ArgTypes…)> ,本类重载了 () 括号运算符函数。所以本模板类的对象可以像函数一样被调用,本类配合 thread 类使用,在新线程里运行函数,而且可以获得函数的返回值。顾名思义:打包任务,打包即将在新线程中执行的函数,以获得函数的返回值:
// 本 packaged_task<T> 模板类仅仅借助 _Packaged_state<T>、_State_manager<P>和future<P>、_Promise<P> 来完成定义;
// 类 _Deferred_async_state<R> 和 _Task_async_state<R> 只由全局 async(..) 函数使用。本模板不予以使用。
template <class> // 模板类的泛化版本,因不使用,所以只有声明,没有定义
class packaged_task; // not defined
// class that defines an asynchronous provider that returns the result of a call to a function object
// 类的实例,该实例定义了一个异步提供程序,该提供程序返回函数对象调用的结果
template <class _Ret, class... _ArgTypes> // 顾名思义,打包任务,打包将在线程中执行的函数,以保存函数返回值
class packaged_task<_Ret(_ArgTypes...)> // 看起来此模板类的特化版本要求模板参数是函数类型
{
public:
using _Ptype = typename _P_arg_type<_Ret>::type; // 转换一下函数的返回值类型:改引用为指针,该 void 为int
// class _State_manager<_Ty> { _Associated_state<_Ty>* _Assoc_state; bool _Get_only_once; };
using _MyStateManagerType = _State_manager<_Ptype>; // 简写类型
// class _Promise<_Ty> { _State_manager<_Ty> _State; bool _Future_retrieved; };
using _MyPromiseType = _Promise<_Ptype>; // 简写类型
// class _Packaged_state<_Ret& (_ArgTypes...)> : public _Associated_state<_Ret*>
using _MyStateType = _Packaged_state<_Ret(_ArgTypes...)>; // 父类 _Packaged_state 级别已内含有函数对象
private:
_MyPromiseType _MyPromise ; // 本模板类和 async(..) 函数一样,内建了 _Promise<_P> 对象
public:
packaged_task() noexcept : _MyPromise(0) {} // 默认构造函数
template <class _Fty2, enable_if_t< // 有参构造函数,要求形参是可调用对象
!is_same_v<_Remove_cvref_t<_Fty2>, packaged_task>, int> = 0> explicit
packaged_task(_Fty2&& _Fnarg) : _MyPromise(new _MyStateType(_STD forward<_Fty2>(_Fnarg))) {}
/*
class _Associated_state { exception_ptr _Exception;
void _Abandon() // 本函的语义可能是当没计算出函数返回值时,本对象就被析构释放,
{ // 则设置 _Associated_state<T>._Exception 成员,以记录此异常情况。
unique_lock<mutex> _Lock(_Mtx);
// 经测试本函代码的完整执行,仍是正常情况,不会导致进程出错退出。
if (!_Has_stored_result) {
future_error _Fut(make_error_code(future_errc::broken_promise));
_Set_exception_raw(_STD make_exception_ptr(_Fut), &_Lock, false); }
}
};
class _State_manager { _Associated_state<_Ty>* _Assoc_state;
void _Abandon() { if (_Assoc_state) _Assoc_state->_Abandon(); } };
class _Promise { _State_manager<_Ty> _State; _State_manager<_Ty>& _Get_state() { return _State; } };
*/
~packaged_task() noexcept { _MyPromise._Get_state()._Abandon(); } // 析构函数
// 说明本 packaged_task<R(A...)> 对象可以像函数一样被调用,且可以接收随时传递的参数
void operator()(_ArgTypes... _Args)
{
// class _Promise { bool _Is_ready() { return _State._Assoc_state->_Ready != 0 ; } };
if (_MyPromise._Is_ready()) // 上面是简化版的代码,求函数返回值前 ...state<R> 不能已存有返回值
_Throw_future_error(make_error_code(future_errc::promise_already_satisfied));
// class _Promise { _State_manager<_Ty>& _Get_state_for_set() { return _State; } };
_MyStateManagerType& _State = _MyPromise._Get_state_for_set(); // 注意:接收值是个左值引用!!
// class _State_manager { _Associated_state<_Ty>* _Ptr() { return _Assoc_state; } };
_MyStateType* _Ptr = static_cast<_MyStateType*>(_State._Ptr()); //把函数返回的爷指针转化为爹指针
_Ptr->_Call_immediate(_STD forward<_ArgTypes>(_Args)...);
/*
template <class _Ret, class... _ArgTypes>
class _Packaged_state<_Ret& (_ArgTypes...)> : public _Associated_state<_Ret*> {
function<_Ret& (_ArgTypes...)> _Fn;
void _Call_immediate(_ArgTypes... _Args) // 实参 false 是 notify_At_thread_exit 的意思
{ this->_Set_value(_STD addressof(_Fn(_STD forward<_ArgTypes>(_Args)...)), false); }
void _Call_deferred(_ArgTypes... _Args)
{ this->_Set_value(_STD addressof(_Fn(_STD forward<_ArgTypes>(_Args)...)), true ); }
};
*/
}
//也是执行本模板封装的函数,但是是调用 _Packaged_state<T> 中的 _Call_deferred 而非 _Call_immediate
void make_ready_at_thread_exit(_ArgTypes... _Args)
{
if (_MyPromise._Is_ready())
_Throw_future_error(make_error_code(future_errc::promise_already_satisfied));
_MyStateManagerType& _State = _MyPromise._Get_state_for_set();
if (_State._Ptr()->_Already_has_stored_result())
_Throw_future_error(make_error_code(future_errc::promise_already_satisfied));
_MyStateType* _Ptr = static_cast<_MyStateType*>(_State._Ptr());
_Ptr->_Call_deferred(_STD forward<_ArgTypes>(_Args)...); // 只有这一行不同于 ()运算符函数
}
packaged_task(const packaged_task&) = delete; // 禁止 copy 构造函数
packaged_task& operator=(const packaged_task&) = delete; // 禁止了 copy 赋值运算符
// class _Promise { _State_manager<_Ty> _State; bool _Future_retrieved; } 移动这俩数据成员即可
packaged_task(packaged_task&& _Other) // 移动构造函数
: _MyPromise(_STD move(_Other._MyPromise)) {}
packaged_task& operator=(packaged_task&& _Other) // 移动赋值运算符函数
{
_MyPromise = _STD move(_Other._MyPromise); return *this;
}
void swap(packaged_task& _Other) { _STD swap(_MyPromise, _Other._MyPromise); }
// class _State_manager { _Associated_state<_Ty>* _Assoc_state; bool _Get_only_once;
// bool valid() { return _Assoc_state && !(_Get_only_once && _Assoc_state->_retrieved ); } };
bool valid() { return _MyPromise._Is_valid(); }
// class _Promise { _State_manager<_Ty> _State; bool _Future_retrieved;
// _State_manager<_Ty>& _Get_state_for_future() { _Future_retrieved = true; return _State; } };
future<_Ret> get_future()
{ return future<_Ret>(_MyPromise._Get_state_for_future(), _Nil()); }
// 此函数含义是 本 packaged_task 管理的函数对象只可以执行一次,函数执行结果存储在 _Associated_state 中;
// 但若想重新运行管理的函数,就释放堆区的 _Packaged_state<T> 对象,再分配一个新的 _Packaged_state<T> 对象 。
void reset() // reset to newly constructed state
{
_MyStateManagerType& _State = _MyPromise._Get_state_for_set();
_MyStateType* _MyState = static_cast<_MyStateType*>(_State._Ptr()); // 爷指针转换为爹指针
// class _Packaged_state<_Ret& (_ArgTypes...)> : public _Associated_state<_Ret*>
// { function<_Ret& (_ArgTypes...)> _Fn; };
function<_Ret(_ArgTypes...)> _Fnarg = _MyState->_Get_fn(); // 重新生成 function 对象
_MyPromiseType _New_promise(new _MyStateType(_Fnarg)); // 这非指针,这是一个数据对象
_MyPromise._Get_state()._Abandon(); // 此局部变量 _New_promise 会在函数退出时析构,
_MyPromise._Swap(_New_promise); // 同时也就回收了堆区中旧的 _Packaged_state 对象
}
};
(39) 接着举例 packaged_task<R(a…)> 的使用,练习使用其成员函数,记忆使用其编写代码的例子:
++ 根据其源代码,还可以延时打印,直到线程结束,才返回函数的返回值:
(40)
谢谢