当前位置: 首页 > news >正文

网站建设整体策划制作网页多少钱

网站建设整体策划,制作网页多少钱,公众号网站,wordpress7比2主题破解版文章目录 八、day81. std::async2. std::future2.1 wait()2.2 get() 八、day8 之前说过#xff0c;std::async内部的处理逻辑和std::thread相似#xff0c;而且std::async和std::future有密不可分的联系。今天#xff0c;通过对std::async和std::future源码进行解析#x… 文章目录 八、day81. std::async2. std::future2.1 wait()2.2 get() 八、day8 之前说过std::async内部的处理逻辑和std::thread相似而且std::async和std::future有密不可分的联系。今天通过对std::async和std::future源码进行解析了解二者的处理逻辑和关系。 源码均基于 MSVC 实现 参考 博主恋恋风辰的个人博客up主mq白cpp的个人仓库 1. std::async std::async有两种重载实现 template class _Fty, class... _ArgTypes _NODISCARD future_Invoke_result_tdecay_t_Fty, decay_t_ArgTypes... async(launch _Policy, _Fty _Fnarg, _ArgTypes... _Args) {// manages a callable object launched with supplied policyusing _Ret _Invoke_result_tdecay_t_Fty, decay_t_ArgTypes...;using _Ptype typename _P_arg_type_Ret::type;_Promise_Ptype _Pr(_Get_associated_state_Ret(_Policy, _Fake_no_copy_callable_adapter_Fty, _ArgTypes...(_STD forward_Fty(_Fnarg), _STD forward_ArgTypes(_Args)...)));return future_Ret(_Pr._Get_state_for_future(), _Nil()); }template class _Fty, class... _ArgTypes _NODISCARD future_Invoke_result_tdecay_t_Fty, decay_t_ArgTypes... async(_Fty _Fnarg, _ArgTypes... _Args) {// manages a callable object launched with default policyreturn _STD async(launch::async | launch::deferred, _STD forward_Fty(_Fnarg), _STD forward_ArgTypes(_Args)...); }第一种重载需要显式指定启动策略也就是我们之前说的std::launch::async、std::launch::deferred和std::launch::async | std::launch::deferred第二种重载在使用默认策略时会被调用也就是只传递可调用对象和参数而不传递启动策略在内部会调用第一种重载并传入一个std::launch::async | std::launch::deferred策略并将参数全部转发。 我们只需要着重关注第一种重载即可 模板参数和函数体外部信息 _Fty可调用对象的类型_ArgTypes可调用对象所需的参数类型_NODISCARD宏用于标记该函数的返回值不应被忽略 返回类型 future_Invoke_result_tdecay_t_Fty, decay_t_ArgTypes...其实就是返回一个 std::future 对象_Invoke_result_tdecay_t_Fty, decay_t_ArgTypes...是std::invoke对给定的可调用对象 _Fnarg 和参数 _Args... 执行后返回的类型其实也就是通过 _Invoke_result_t 从 _Fty 和 _ArgTypes... 中推导出的返回类型。 我们之前在thread源码解析中说过std::invoke内部其实是调用_Call函数_Call函数负责提供参数并调用传入的可调用对象。 我们可以把 _Invoke_result_t 看作是一个对 std::invoke 的结果类型的封装std::invoke 是一个工具可以调用可调用对象并返回其结果。_Invoke_result_t 提供了一种方式来“推导”出这个结果类型。 这个类型萃取工具通常长这样简化版 template typename _Callable, typename... _Args struct _Invoke_result_t {using type decltype(std::invoke(std::declval_Callable(), std::declval_Args()...)); };上述代码通过 std::invoke 来推导decltype _Callable即可调用对象在给定参数 _Args... 上执行后的返回类型。换句话说_Invoke_result_t_Fty, _ArgTypes... 的 type 成员类型就是可调用对象在调用后的返回类型。 值得注意的是所有类型在传递前都进行了 decay 处理也就是将cv和const修饰符去掉默认按值传递与 std::thread 的行为一致。 形参 future_Ret async(launch _Policy, _Fty _Fnarg, _ArgTypes... _Args) {}launch _Policy: 表示任务的执行策略可以是 launch::async表示异步执行或 launch::deferred表示延迟执行或者std::launch::async | std::launch::deferred_Fty _Fnarg: 可调用对象通过完美转发机制将其转发给实际的异步任务_ArgTypes... _Args: 调用该可调用对象时所需的参数同样通过完美转发机制进行转发 _Ret和_Ptype _Ret就算我们在返回类型中说到的_Invoke_result_tdecay_t_Fty, decay_t_ArgTypes...表示可调用对象的返回类型 using _Ptype typename _P_arg_type_Ret::type_Ptype 的定义在大多数情况下和 _Ret 是相同的类模板 _P_arg_type 只是为了处理引用类型以及 void 的情况参见 _P_arg_type 的实现 template class _Fret struct _P_arg_type { // type for functions returning Tusing type _Fret; };template class _Fret struct _P_arg_type_Fret { // type for functions returning reference to Tusing type _Fret*; };template struct _P_arg_typevoid { // type for functions returning voidusing type int; };为什么需要 _Ptype 在异步任务的实现中std::promise 是用于将结果与 std::future 绑定的对象。std::promise 的模板参数通常是可调用对象返回值的类型。在 std::async 函数中我们需要创建一个 std::promise 对象来存储任务的结果因此我们需要计算出正确的承诺类型promise type。也就是说定义 _Ptype 是为了配合后面 _Promise 的使用确保任务的结果可以通过 std::future 获取。 _Ret 是任务返回的类型由 _Invoke_result_t 推导出。 _Ptype 就是这个返回类型的承诺类型。也就是说**_Ptype 是 std::promise 的模板参数类型**表示这个任务结果的类型。 _Ptype 的定义在大多数情况下和 _Ret 是相同的都是可调用对象返回值的类型。 _Promise_Ptype _Pr创建一个 std::promise 对象 _Pr其类型为 _Ptype表示与异步任务的结果相关联的承诺promise。_Promise类型我们之前讲过这里就不在叙述它的作用关键还在于其存储的数据成员 template class _Ty class _Promise { public:_Promise(_Associated_state_Ty* _State_ptr) : _State(_State_ptr, false), _Future_retrieved(false) {}_Promise(_Promise _Other) : _State(_STD move(_Other._State)), _Future_retrieved(_Other._Future_retrieved) {}_Promise operator(_Promise _Other) {_State _STD move(_Other._State);_Future_retrieved _Other._Future_retrieved;return *this;}~_Promise() noexcept {}void _Swap(_Promise _Other) {_State._Swap(_Other._State);_STD swap(_Future_retrieved, _Other._Future_retrieved);}const _State_manager_Ty _Get_state() const {return _State;}_State_manager_Ty _Get_state() {return _State;}_State_manager_Ty _Get_state_for_set() {if (!_State.valid()) {_Throw_future_error(make_error_code(future_errc::no_state));}return _State;}_State_manager_Ty _Get_state_for_future() {if (!_State.valid()) {_Throw_future_error(make_error_code(future_errc::no_state));}if (_Future_retrieved) {_Throw_future_error(make_error_code(future_errc::future_already_retrieved));}_Future_retrieved true;return _State;}bool _Is_valid() const noexcept {return _State.valid();}bool _Is_ready() const {return _State._Is_ready();}bool _Is_ready_at_thread_exit() const {return _State._Is_ready_at_thread_exit();}_Promise(const _Promise) delete;_Promise operator(const _Promise) delete;private:_State_manager_Ty _State;bool _Future_retrieved; };注意_Promise 和 std::promise 并不是同一个模板类_Promise是为了提供对 std::promise 的进一步定制并不是std::primse本身。std::primise模板类的私有成员是通过_Promise声明的即 // std::primise 的私有成员 private:_Promise_Ty* _MyPromise;_Promise 类模板是对_State_manager类模板的包装并增加了一个表示状态的私有成员 _Future_retrieved。 private:_State_manager_Ty _State;bool _Future_retrieved;状态成员用于跟踪 _Promise 是否已经调用过 _Get_state_for_future() 成员函数它默认为 false在第一次调用 _Get_state_for_future() 成员函数时被置为 true如果二次调用就会抛出future_errc::future_already_retrieved异常。 _Promise 的构造函数接受的不是_State_manager 类型的对象而是_Associated_state 类型的指针用来初始化数据成员 _State。 _Promise(_Associated_state_Ty* _State_ptr) : _State(_State_ptr, false), _Future_retrieved(false) {}这是因为实际上_State_manager类型只有两个私有成员Associated_state指针以及一个状态成员 private:_Associated_state_Ty* _Assoc_state;bool _Get_only_once;可以简单理解为 _State_manager 是对 Associated_state 的包装其中的大部分接口实际上是调用 _Assoc_state 的成员函数你们可以去_State_manager的实现源码中查阅大部分接口其实都是通过调用_Assoc_state实现的。 所以在解析std::async源码之前我们必须对Associated_state有一个清晰的了解 public:_Ty _Result;exception_ptr _Exception;mutex _Mtx;condition_variable _Cond;bool _Retrieved;int _Ready;bool _Ready_at_thread_exit;bool _Has_stored_result;bool _Running;这是Associated_state模板类主要的成员变量我没有全部列上去只列了主要的其中最为重要的三个变量是异常指针、互斥量、条件变量。 其实_Associated_state 模板类负责管理异步任务的状态包括结果的存储、异常的处理以及任务完成的通知。它是实现 std::future 和 std::promise 的核心组件之一通过 _State_manager 和 _Promise 类模板对其进行封装和管理提供更高级别的接口和功能。 _Promise、_State_manager、_Associated_state 之间的包含关系如上述结构所示。 初始化 _Promise 对象 _Promise_Ptype _Pr(_Get_associated_state_Ret(_Policy, _Fake_no_copy_callable_adapter_Fty, _ArgTypes...(_STD forward_Fty(_Fnarg), _STD forward_ArgTypes(_Args)...)) );这是一个函数调用将我们 std::async 的参数全部转发给它。 首先将参数 _Fnarg 可调用对象和 _Args...传入可调用对象的参数包 通过 std::forward 转发给 _Fake_no_copy_callable_adapter。然后_Fake_no_copy_callable_adapter 创建一个可调用对象函数适配器。接着适配器和指定的启动策略被传递给 _Get_associated_state 函数目的是获取与异步操作相关的状态。最终_Get_associated_state 返回一个与异步操作相关的状态并将其传递给 _Pr这将会返回一个 _Promise_Ptype代表一个异步操作的结果。 _Get_associated_state函数根据启动模式_Policy有三种来决定创建的异步任务状态对象类型 template class _Ret, class _Fty _Associated_statetypename _P_arg_type_Ret::type* _Get_associated_state(launch _Psync, _Fty _Fnarg) {// construct associated asynchronous state object for the launch typeswitch (_Psync) { // select launch typecase launch::deferred:return new _Deferred_async_state_Ret(_STD forward_Fty(_Fnarg));case launch::async: // TRANSITION, fixed in vMajorNext, should create a new thread heredefault:return new _Task_async_state_Ret(_STD forward_Fty(_Fnarg));} }_Get_associated_state 函数返回一个 _Associated_state 指针 _Associated_state 可用于初始化_State_manager_State_manager可用于初始化_Promise该指针指向一个新的 _Deferred_async_state 或_Task_async_state 对象。这两个类分别对应于异步任务的两种不同执行策略延迟执行和异步执行。 这段代码也很好的说明launch::async | launch::deferred 和 launch::async 的行为是相同的都会创建新线程异步执行任务只不过前者会自行判断系统资源来抉择。 _Task_async_state 与 _Deferred_async_state 都继承自 _Packaged_state其用于异步执行任务。它们的构造函数都接受一个函数对象并将其转发给基类 _Packaged_state 的构造函数。 // _Task_async_state 的构造函数 template class _Rx class _Task_async_state : public _Packaged_state_Rx() // _Deferred_async_state 的构造函数 template class _Rx class _Deferred_async_state : public _Packaged_state_Rx()_Packaged_state 类型只有一个数据成员 std::function 类型的对象 _Fn它用来存储需要执行的异步任务而它又继承自 _Associated_state。 template class _Ret, class... _ArgTypes class _Packaged_state_Ret(_ArgTypes...): public _Associated_state_Ret如上图所示_Task_async_state 与 _Deferred_async_state 都继承自 _Packaged_state _Packaged_state中保存了传入给std::async的可调用对象。同时_Packaged_state继承自_Associated_state_Associated_state 是_Primise类中成员_State的最基本组成对象基本所有的接口都是通过调用_Associated_state 的函数实现的。 _Task_async_state 与 _Deferred_async_state 的构造函数如下 // _Task_async_state template class _Fty2 _Task_async_state(_Fty2 _Fnarg) : _Mybase(_STD forward_Fty2(_Fnarg)) {_Task ::Concurrency::create_task([this]() { // do it nowthis-_Call_immediate();});this-_Running true; } // _Deferred_async_state template class _Fty2 _Deferred_async_state(const _Fty2 _Fnarg) : _Packaged_state_Rx()(_Fnarg) {} template class _Fty2 _Deferred_async_state(_Fty2 _Fnarg) : _Packaged_state_Rx()(_STD forward_Fty2(_Fnarg)) {}a. _Task_async_state _Task_async_state有一个数据成员_Task用于从线程池中获取线程并执行可调用对象 private:::Concurrency::taskvoid _Task;_Task_async_state 的实现使用了微软实现的并行模式库PPL。简而言之 launch::async 策略并不是单纯的创建线程让任务执行而是使用了微软的 ::Concurrency::create_task 它从线程池中获取线程并执行任务返回包装对象。 this-_Call_immediate()是调用 _Task_async_state 的父类 _Packaged_state 的成员函数 _Call_immediate. _Packaged_state有三个版本自然_Call_immediate也有三种版本用于处理可调用对象返回类型的三种情况 // 返回普通类型 // class _Packaged_statevoid(_ArgTypes...) void _Call_immediate(_ArgTypes... _Args) {_TRY_BEGIN// 调用函数对象并捕获异常 传递返回值this-_Set_value(_Fn(_STD forward_ArgTypes(_Args)...), false);_CATCH_ALL// 函数对象抛出异常就记录this-_Set_exception(_STD current_exception(), false);_CATCH_END }// 返回引用类型 // class _Packaged_state_Ret(_ArgTypes...) void _Call_immediate(_ArgTypes... _Args) {_TRY_BEGIN// 调用函数对象并捕获异常 传递返回值的地址this-_Set_value(_STD addressof(_Fn(_STD forward_ArgTypes(_Args)...)), false);_CATCH_ALL// 函数对象抛出异常就记录this-_Set_exception(_STD current_exception(), false);_CATCH_END }// 返回void类型 // class _Packaged_statevoid(_ArgTypes...) void _Call_immediate(_ArgTypes... _Args) { _TRY_BEGIN// 调用函数对象并捕获异常 因为返回 void 不获取返回值 而是直接 _Set_value 传递一个 1_Fn(_STD forward_ArgTypes(_Args)...);this-_Set_value(1, false);_CATCH_ALL// 函数对象抛出异常就记录this-_Set_exception(_STD current_exception(), false);_CATCH_END }_Fn(_STD forward_ArgTypes(_Args)...表示执行可调用对象this-_Set_value(_Fn(_STD forward_ArgTypes(_Args)...)表示将可调用对象的返回值传入给_Set_value其他两个函数也是类似的处理过程。 _TRY_BEGIN、_CATCH_ALL、_CATCH_END类似try-catch块。当 _Fn 函数对象抛出异常时控制流会跳转到 _CATCH_ALL 代码块this-_Set_exception用来记录当前捕获的异常;_CATCH_END 标识异常处理的结束因为返回类型为void 表示不获取返回值所以这里通过_Set_value 传递一个 1表示正确执行的状态。所有的返回值均传入给_Set_value 。 简而言之就是把返回引用类型的可调用对象返回值的引用获取地址传递给 _Set_value把返回 void 类型的可调用对象传递一个 1 表示正确执行的状态给 _Set_value。 _Set_value、_set_exception函数来自_Packaged_state模板类的父类_Associated_state通过这两个函数传递的可调用对象执行结果以及可能的异常并将结果或异常存储在 _Associated_state 中。 b. _Deferred_async_state _Deferred_async_state 并不会从线程池中获取一个新线程然后再新线程中执行任务而是当前线程调用future的get或者wait函数时在当前线程中同步执行。但它同样调用 _Call_immediate 函数执行存储的可调用对象它有一个 _Run_deferred_function 函数 void _Run_deferred_function(unique_lockmutex _Lock) override { // run the deferred function_Lock.unlock();_Packaged_state_Rx()::_Call_immediate();_Lock.lock(); }然后通过 _Call_immediate调用可调用对象并通过函数_Set_value、_set_exception存储可调用对象返回结果或者异常至_Associated_state。 返回 std::future return future_Ret(_Pr._Get_state_for_future(), _Nil());_Ret在前面说了其实就是可调用对象返回值的类型。 传给future构造函数的参数之一是_Pr._Get_state_for_future()调用上面构造的_Promise的成员函数_Get_state_for_future该函数用于返回_Promise类的私有成员变量_State。 _Get_state_for_future函数的实现如下 _State_manager_Ty _Get_state_for_future() {if (!_State.valid()) {_Throw_future_error2(future_errc::no_state);}if (_Future_retrieved) {_Throw_future_error2(future_errc::future_already_retrieved);}_Future_retrieved true;return _State; }其实就是调用_State的成员函数valid()检查状态是否有错然后判断future是否提前返回可调用对象的返回值如果是代表future的get被调用抛出异常最后返回_State。 2. std::future 我们首先从一个最简单的std::async示例开始 std::futureint future std::async([] { return 0; }); future.get();我们从之前的学习中了解到future.get()就是从future中获取可调用对象的返回结果。唯一的问题是future.get() 内部执行了什么流程首先从future的实现开始 _EXPORT_STD template class _Ty class future : public _State_manager_Ty {// class that defines a non-copyable asynchronous return object that holds a value private:using _Mybase _State_manager_Ty;public:static_assert(!is_array_v_Ty is_object_v_Ty is_destructible_v_Ty,T in futureT must meet the Cpp17Destructible requirements (N4950 [futures.unique.future]/4).);future() default;future(future _Other) noexcept : _Mybase(_STD move(_Other), true) {}future operator(future) default;future(_From_raw_state_tag, const _Mybase _State) noexcept : _Mybase(_State, true) {}_Ty get() {// block until ready then return the stored result or throw the stored exceptionfuture _Local{_STD move(*this)};return _STD move(_Local._Get_value());}_NODISCARD shared_future_Ty share() noexcept {return shared_future_Ty(_STD move(*this));}future(const future) delete;future operator(const future) delete; };future类继承自_State_manager类_State_manager类又有一个_Associated_state_Ty*类型的私有成员_State而_State_manager的接口实现大部分是通过调用_Associated_state 的成员函数实现的。关系如下 2.1 wait() 但你可能发现一个问题future类怎么没有wait()成员函数其实wait()函数继承自父类_State_manager。 void wait() const { // wait for signalif (!valid()) {_Throw_future_error2(future_errc::no_state);}_Assoc_state-_Wait(); }而_State_manager类的wait()其实是通过调用_Associated_state的接口实现的所以说_Associated_state在std::async和std::future中是非常核心的。 virtual void _Wait() { // wait for signalunique_lockmutex _Lock(_Mtx);_Maybe_run_deferred_function(_Lock);while (!_Ready) {_Cond.wait(_Lock);} }_Associated_state的wait()函数通过unique_lock保护共享数据然后调用_Maybe_run_deferred_function执行可调用对象直至调用结束。 void _Maybe_run_deferred_function(unique_lockmutex _Lock) { // run a deferred function if not already doneif (!_Running) { // run the function_Running true;_Run_deferred_function(_Lock);} }_Maybe_run_deferred_function其实就是通过调用_Run_deferred_function来调用_Call_immediate()我们在async源码中学习过_Run_deferred_function和_Call_immediate()。 void _Run_deferred_function(unique_lockmutex _Lock) override { // run the deferred function_Lock.unlock();_Packaged_state_Rx()::_Call_immediate();_Lock.lock(); }在 _Wait 函数中调用 _Maybe_run_deferred_function 是为了确保延迟执行launch::deferred的任务能够在等待前被启动并执行完毕。这样在调用 wait 时可以正确地等待任务完成。 因为只有std::launch::deferred才是当调用future.get或者wait时才会执行_Call_immediate()其他两种启动策略在大部分情况下都是直接执行通过future.get获得结果。所以我们必须保证在调用wait函数时执行std::launch::deferred策略的任务被执行而其他两种启动策略早已经执行任务无需再调用_Call_immediate()。所以在_Maybe_run_deferred_function函数中有下面一段判断任务是否以及执行如果被执行那么久就不调用_Call_immediate反之调用。 if (!_Running) { // run the function_Running true;_Run_deferred_function(_Lock);while (!_Ready) {_Cond.wait(_Lock);}通过条件变量挂起当前线程等待可调用对象执行完毕。在等待期间当前线程释放持有的锁保证其他线程再次期间可以访问到共享资源待当前线程被唤醒后重新持有锁。其主要作用是 避免虚假唤醒 条件变量的 wait 函数在被唤醒后会重新检查条件即 _Ready 是否为 true确保只有在条件满足时才会继续执行。这防止了由于虚假唤醒导致的错误行为。 等待 launch::async 的任务在其它线程执行完毕 对于 launch::async 模式的任务这段代码确保当前线程会等待任务在另一个线程中执行完毕并接收到任务完成的信号。只有当任务完成并设置 _Ready 为 true 后条件变量才会被通知从而结束等待。 这样当调用 wait 函数时可以保证无论任务是 launch::deferred 还是 launch::async 模式当前线程都会正确地等待任务的完成信号然后继续执行。 std::future 其实还有两种特化不过整体大差不差。 template class _Ty class future_Ty : public _State_manager_Ty*template class futurevoid : public _State_managerint也就是对返回类型为引用和 void 的情况了。其实先前已经聊过很多次了无非就是内部的返回引用实际按指针操作返回 void那么也得给个 1表示正常运行的状态。类似于前面 _Call_immediate 的实现。 2.2 get() get()函数是future的成员函数而没有继承父类_State_manager // std::futurevoid void get() {// block until ready then return or throw the stored exceptionfuture _Local{_STD move(*this)};_Local._Get_value(); } // std::futureT _Ty get() {// block until ready then return the stored result or throw the stored exceptionfuture _Local{_STD move(*this)};return _STD move(_Local._Get_value()); } // std::futureT _Ty get() {// block until ready then return the stored result or throw the stored exceptionfuture _Local{_STD move(*this)};return *_Local._Get_value(); }因为future有三种特化所以get()函数也有三种特化。它们将当前future对象的指针通过std::move转移给类型为future的局部变量_Local转移后原本的future对象便失去了所有权。然后局部变量_Local调用成员函数_Get_value()并将结果返回。 注意局部对象 _Local 在函数结束时析构。这意味着当前对象*this失去共享状态并且状态被完全销毁。 _Get_value() 函数的实现如下 _Ty _Get_value() const {if (!valid()) {_Throw_future_error2(future_errc::no_state);}return _Assoc_state-_Get_value(_Get_only_once); }future.valid() 成员函数检查 future 当前是否关联共享状态即是否当前关联任务。如果还未关联或者任务已经执行完调用了 get()、set()都会返回 false。 首先通过valid()判断当前future对象是否关联共享状态如果没抛出异常。最后调用 _Assoc_state 的成员函数 _Get_value 传递 _Get_only_once 参数其实就是代表这个成员函数只能调用一次。 _Assoc_state 的类型是 _Associated_state_Ty* 是一个指针类型它实际会指向自己的子类对象我们在讲 std::async 源码的时候提到了它必然指向 _Deferred_async_state 或者 _Task_async_state。 _Assoc_state-_Get_value 这其实是个多态调用父类有这个虚函数 virtual _Ty _Get_value(bool _Get_only_once) {unique_lockmutex _Lock(_Mtx);if (_Get_only_once _Retrieved) {_Throw_future_error2(future_errc::future_already_retrieved);}if (_Exception) {_STD rethrow_exception(_Exception);}// TRANSITION: _Retrieved should be assigned before _Exception is thrown so that a future::get// that throws a stored exception invalidates the future (N4950 [futures.unique.future]/17)_Retrieved true;_Maybe_run_deferred_function(_Lock);while (!_Ready) {_Cond.wait(_Lock);}if (_Exception) {_STD rethrow_exception(_Exception);}if constexpr (is_default_constructible_v_Ty) {return _Result;} else {return _Result._Held_value;} }子类 _Task_async_state 对其进行了重写以 launch::async 策略或者std::launch::async | std::launch::deferred策略创建的future实际会调用 _Task_async_state::_Get_value _State_type _Get_value(bool _Get_only_once) override {// return the stored result or throw stored exception_Task.wait();return _Mybase::_Get_value(_Get_only_once); }_Deferred_async_state 没有对其进行重写直接调用父类虚函数。 _Task 就是 ::Concurrency::taskvoid _Task;调用 wait() 成员函数确保任务执行完毕。 _Mybase::_Get_value(_Get_only_once) 其实又是回去调用父类的虚函数了。 _Get_value 方法详解 _Get_value()只能调用一次 如果 _Get_only_once 为 true 且 _Retrieved 为 true表示结果已经被检索过则抛出 future_already_retrieved 错误。 处理异常 如果在获取结果过程中出现了异常需要重新抛出该异常 设置 _Retrieved 为 true 在获取值之前设置 _Retrieved 为 true表示结果已经被检索过。这样可以确保 future 对象不会被重复获取避免多次调用 get 时引发错误。 执行延迟函数 调用_Maybe_run_deferred_function来运行可能的延迟任务。在该函数内部如果任务已经运行那么退出如果没运行调用_Call_immediate()函数执行可调用对象。 等待结果 使用条件变量挂起当前线程确保线程同步即只有当异步任务准备好返回结果时线程才会继续执行。 再次检查异常 线程被唤醒将结果存储至future对象中后再次判断是否发生了异常需要重新抛出异常 返回结果 这部分代码根据 _Ty 类型的特性决定如何返回结果 如果 _Ty 类型是 默认可构造即 _Ty 的默认构造函数有效直接返回 _Result。否则返回 _Result._Held_value is_default_constructible_v_Ty 是一个 C17 引入的类型特征用于检查类型 _Ty 是否具有默认构造函数。 _Result 是 future 中持有的结果而 _Held_value 是存储在 _Result 中的实际值。 _Result 是通过执行 _Call_immediate 函数然后 _Call_immediate 再执行 _Set_value _Set_value 再执行 _Set_value_raw_Set_value_raw再执行_Emplace_result并通知线程可以醒来_Emplace_result 获取到我们执行任务的返回值的。以 Ty 的偏特化为例 // _Packaged_state void _Call_immediate(_ArgTypes... _Args) {_TRY_BEGIN// 调用函数对象并捕获异常 传递返回值this-_Set_value(_Fn(_STD forward_ArgTypes(_Args)...), false);_CATCH_ALL// 函数对象抛出异常就记录this-_Set_exception(_STD current_exception(), false);_CATCH_END }// _Asscoiated_state void _Set_value(const _Ty _Val, bool _At_thread_exit) { // store a resultunique_lockmutex _Lock(_Mtx);_Set_value_raw(_Val, _Lock, _At_thread_exit); } void _Set_value_raw(const _Ty _Val, unique_lockmutex* _Lock, bool _At_thread_exit) {// store a result while inside a locked blockif (_Already_has_stored_result()) {_Throw_future_error2(future_errc::promise_already_satisfied);}_Emplace_result(_Val);_Do_notify(_Lock, _At_thread_exit); } template class _Ty2 void _Emplace_result(_Ty2 _Val) {// TRANSITION, incorrectly assigns _Result when _Ty is default constructibleif constexpr (is_default_constructible_v_Ty) {_Result _STD forward_Ty2(_Val); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!} else {::new (static_castvoid*(_STD addressof(_Result._Held_value))) _Ty(_STD forward_Ty2(_Val));_Has_stored_result true;} }
http://www.hkea.cn/news/14312846/

相关文章:

  • 贞丰县建设局网站wordpress如何适配手机
  • 上海 专业网站设计 母婴类百度小程序制作
  • 网站红蓝色配色分析网站空间是不是服务器
  • 开发区网站建设delphi 网站开发
  • 网站备案需要花钱吗贵州省城乡建设厅网站材料价
  • flash做网站轮播图wordpress前台登录认证失败
  • 云南省建设网站百度网站建设前期都有哪些费用
  • 滕州做网站的创新的商城网站建设
  • 网站建设对于企业发展的优势wordpress清理插件
  • 怎么建立网站 个人热点网站设计制作在哪能看
  • 重庆网站备案注销wordpress attachment
  • 网站1g的空间能用多久建设主管部门指定网站
  • 网站基础知识域名5个点秦皇岛市属于哪个省
  • 泰安微信网站制作百度推广如何计费
  • 哪个网站开发是按月付费的运营推广怎么做
  • 莆田网站建设维护什么行业适合做网站推广
  • 做效果图的网站wordpress文件核对
  • 域名注册后能开始建设网站吗wordpress免费域名
  • 掼蛋网站建设面试学校网站开发
  • 湖南建设监理官方网站建筑网方成龙
  • 两个男性做网站重复建设政务网站
  • 网站开发语言有几种wordpress站群模板
  • 设计接活的网站长沙竞价优化
  • php网站开发视频网站泰安招聘信息最新招聘2023
  • 太原定制网站建设制作公司已备案个人网站做淘宝客
  • 同学录网站开发实现基本要求免费软件app不收费的
  • 做网站的人月所有复刻手表网站
  • 郑州网站建设蝶动科技网站建设的所有权
  • 网站的模板演示怎么做论坛网站建设公司
  • 做网站工作室找客户难关于网站seo优化