<future> 注释11:全函 async () 的使用举例与验证,用 async (..)就不需要用 join ( ) 了,模板类 packaged_task<R(a...)>及举例

(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)

谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值