@@ -273,6 +273,8 @@ _NODISCARD_ASYNC future<_Invoke_result_t<decay_t<_Fty>, decay_t<_ArgTypes>...>>
273273
274274 `_Get_associated_state` 函数返回一个 `_Associated_state` 指针,该指针指向一个新的 `_Deferred_async_state` 或 `_Task_async_state` 对象。这两个类分别对应于异步任务的两种不同执行策略:**延迟执行**和**异步执行**。
275275
276+ > 其实就是父类指针指向了子类对象,注意 **`_Associated_state` 是有虚函数的**,子类进行覆盖,这很重要。比如在后续聊 `std::future` 的 `get()` 成员函数的时候就会讲到
277+
276278 > 这段代码也很好的说明在 MSVC STL 中,`launch::async | launch::deferred` 和 `launch::async` 的行为是相同的,即都是异步执行。
277279
278280 ---
@@ -580,7 +582,7 @@ virtual void _Wait() { // wait for signal
580582}
581583```
582584
583- 先使用锁进行保护,然后调用函数,再循环等待任务执行完毕。关键实际上在于 ` _Maybe_run_deferred_function ` :
585+ 先使用锁进行保护,然后调用函数,再循环等待任务执行完毕。` _Maybe_run_deferred_function ` :
584586
585587``` cpp
586588void _Maybe_run_deferred_function (unique_lock<mutex >& _ Lock) { // run a deferred function if not already done
@@ -591,4 +593,202 @@ void _Maybe_run_deferred_function(unique_lock<mutex>& _Lock) { // run a deferred
591593}
592594```
593595
594- `_Run_deferred_function` 相信你不会陌生,在讲述 `std::async` 源码中其实已经提到了。
596+ `_Run_deferred_function` 相信你不会陌生,在讲述 `std::async` 源码中其实已经提到了,就是解锁然后调用 `_Call_immediate` 罢了。
597+
598+ ```cpp
599+ void _Run_deferred_function(unique_lock<mutex>& _Lock) override { // run the deferred function
600+ _Lock.unlock();
601+ _Packaged_state<_Rx()>::_Call_immediate();
602+ _Lock.lock();
603+ }
604+ ```
605+
606+ > ` _Call_immediate ` 就是执行我们实际传入的函数对象,先前已经提过。
607+
608+ 在 ` _Wait ` 函数中调用 ` _Maybe_run_deferred_function ` 是为了确保延迟执行(` launch::deferred ` )的任务能够在等待前被启动并执行完毕。这样,在调用 ` wait ` 时可以正确地等待任务完成。
609+
610+ 至于下面的循环等待部分:
611+
612+ ``` cpp
613+ while (!_Ready) {
614+ _Cond.wait(_Lock);
615+ }
616+ ```
617+
618+ 这段代码使用了条件变量、互斥量、以及一个状态对象,主要目的有两个:
619+
620+ 1 . ** 避免虚假唤醒** :
621+ - 条件变量的 ` wait ` 函数在被唤醒后,会重新检查条件(即 ` _Ready ` 是否为 ` true ` ),确保只有在条件满足时才会继续执行。这防止了由于虚假唤醒导致的错误行为。
622+ 2 . ** 等待 ` launch::async ` 的任务在其它线程执行完毕** :
623+ - 对于 ` launch::async ` 模式的任务,这段代码确保当前线程会等待任务在另一个线程中执行完毕,并接收到任务完成的信号。只有当任务完成并设置 ` _Ready ` 为 ` true ` 后,条件变量才会被通知,从而结束等待。
624+
625+ 这样,当调用 ` wait ` 函数时,可以保证无论任务是 ` launch::deferred ` 还是 ` launch::async ` 模式,当前线程都会正确地等待任务的完成信号,然后继续执行。
626+
627+ ---
628+
629+ ` wait() ` 介绍完了,那么接下来就是 ` get() ` :
630+
631+ ``` cpp
632+ // std::future<void>
633+ void get () {
634+ // block until ready then return or throw the stored exception
635+ future _Local{_STD move(*this)};
636+ _Local._Get_value();
637+ }
638+ // std::future<T>
639+ _Ty get () {
640+ // block until ready then return the stored result or throw the stored exception
641+ future _Local{_STD move(*this)};
642+ return _STD move(_Local._Get_value());
643+ }
644+ // std::future<T&>
645+ _Ty& get () {
646+ // block until ready then return the stored result or throw the stored exception
647+ future _Local{_STD move(*this)};
648+ return *_Local._Get_value();
649+ }
650+ ```
651+
652+ 在第四章的 “* future 的状态变化* ”一节中我们也详细聊过 ` get() ` 成员函数。由于 future 本身有三个特化,` get() ` 成员函数自然那也有三个版本,不过总体并无多大区别。
653+
654+ 它们都是将当前对象(` *this ` )的共享状态转移给了这个局部对象 ` _Local ` ,然后再去调用父类` _State_manager ` 的成员函数 ` _Get_value() ` 获取值并返回。而局部对象 ` _Local ` 在函数结束时析构。这意味着当前对象(` *this ` )失去共享状态,并且状态被完全销毁。
655+
656+ ` _Get_value() ` :
657+
658+ ``` cpp
659+ _Ty& _Get_value () const {
660+ if (!valid()) {
661+ _Throw_future_error2 (future_errc::no_state);
662+ }
663+
664+ return _Assoc_state->_Get_value(_Get_only_once);
665+ }
666+ ```
667+
668+ 先进行一下状态判断,如果拥有共享状态则继续,调用 ` _Assoc_state ` 的成员函数 ` _Get_value ` ,传递 ` _Get_only_once ` 参数,其实就是代表这个成员函数只能调用一次,次参数是里面进行状态判断的而已。
669+
670+ ` _Assoc_state ` 的类型是 ` _Associated_state<_Ty>* ` ,是一个指针类型,它实际会指向自己的子类对象,我们在讲 ` std::async ` 源码的时候提到了,它必然指向 ` _Deferred_async_state ` 或者 ` _Task_async_state ` 。
671+
672+ ` _Assoc_state->_Get_value ` 这其实是个多态调用,父类有这个虚函数:
673+
674+ ``` cpp
675+ virtual _Ty& _Get_value (bool _ Get_only_once) {
676+ unique_lock<mutex > _ Lock(_ Mtx);
677+ if (_ Get_only_once && _ Retrieved) {
678+ _ Throw_future_error2(future_errc::future_already_retrieved);
679+ }
680+
681+ if (_Exception) {
682+ _STD rethrow_exception(_Exception);
683+ }
684+
685+ // TRANSITION: `_Retrieved` should be assigned before `_Exception` is thrown so that a `future::get`
686+ // that throws a stored exception invalidates the future (N4950 [futures.unique.future]/17)
687+ _Retrieved = true;
688+ _Maybe_run_deferred_function(_Lock);
689+ while (!_Ready) {
690+ _Cond.wait(_Lock);
691+ }
692+
693+ if (_Exception) {
694+ _STD rethrow_exception(_Exception);
695+ }
696+
697+ if constexpr (is_default_constructible_v<_Ty>) {
698+ return _Result;
699+ } else {
700+ return _Result._Held_value;
701+ }
702+ }
703+
704+ ```
705+
706+ 但是子类 `_Task_async_state` 进行了重写,以 `launch::async` 策略创建的 future,那么实际会调用 `_Task_async_state::_Get_value` :
707+
708+ ```cpp
709+ _State_type& _Get_value(bool _Get_only_once) override {
710+ // return the stored result or throw stored exception
711+ _Task.wait();
712+ return _Mybase::_Get_value(_Get_only_once);
713+ }
714+ ```
715+
716+ > ` _Deferred_async_state ` 则没有进行重写,就是直接调用父类虚函数。
717+
718+ ` _Task ` 就是 ` ::Concurrency::task<void> _Task; ` ,调用 ` wait() ` 成员函数确保任务执行完毕。
719+
720+ ` _Mybase::_Get_value(_Get_only_once) ` 其实又是回去调用父类的虚函数了。
721+
722+ > ### ` _Get_value ` 方法详细解释
723+
724+ 1 . ** 状态检查** :
725+ - 如果` _Get_only_once ` 为真并且结果已被检索过,则抛出` future_already_retrieved ` 异常。
726+ 2 . ** 异常处理** :
727+ - 如果存在存储的异常,重新抛出该异常。
728+ 3 . ** 标记结果已被检索** :
729+ - 将` _Retrieved ` 设置为` true ` 。
730+ 4 . ** 执行延迟函数** :
731+ - 调用` _Maybe_run_deferred_function ` 来运行可能的延迟任务。这个函数很简单,就是单纯的执行延时任务而已,在讲述 ` wait ` 成员函数的时候已经讲完了。
732+ 5 . ** 等待结果就绪** :
733+ - 如果结果尚未准备好,等待条件变量通知结果已就绪。(这里和 ` std::async ` 和 ` std::future ` 的组合无关,因为如果是 ` launch::async ` 模式创建的任务,重写的 ` _Get_value ` 是先调用了 ` _Task.wait(); ` 确保异步任务执行完毕,此处根本无需等待它)
734+ 6 . ** 再次检查异常** :
735+ - 再次检查是否有存储的异常,并重新抛出它。
736+ 7 . ** 返回结果** :
737+ - 如果` _Ty ` 是默认可构造的,返回结果` _Result ` 。
738+ - 否则,返回` _Result._Held_value ` 。
739+
740+ ` _Result ` 是通过执行 ` _Call_immediate ` 函数,然后 ` _Call_immediate ` 再执行 ` _Set_value ` ,` _Set_value ` 再执行 ` _Emplace_result ` ,` _Emplace_result ` 再执行 ` _Emplace_result ` 获取到我们执行任务的值的。以 ` Ty ` 的偏特化为例:
741+
742+ ``` cpp
743+ // _Packaged_state
744+ void _Call_immediate (_ ArgTypes... _ Args) {
745+ _ TRY_BEGIN
746+ // 调用函数对象并捕获异常 传递返回值
747+ this->_ Set_value(_ Fn(_ STD forward<_ ArgTypes>(_ Args)...), false);
748+ _ CATCH_ALL
749+ // 函数对象抛出异常就记录
750+ this->_ Set_exception(_ STD current_exception(), false);
751+ _ CATCH_END
752+ }
753+
754+ // _ Asscoiated_state
755+ void _ Set_value(const _ Ty& _ Val, bool _ At_thread_exit) { // store a result
756+ unique_lock<mutex > _ Lock(_ Mtx);
757+ _ Set_value_raw(_ Val, &_ Lock, _ At_thread_exit);
758+ }
759+ void _ Set_value_raw(const _ Ty& _ Val, unique_lock<mutex >* _ Lock, bool _ At_thread_exit) {
760+ // store a result while inside a locked block
761+ if (_ Already_has_stored_result()) {
762+ _ Throw_future_error2(future_errc::promise_already_satisfied);
763+ }
764+
765+ _Emplace_result(_Val);
766+ _Do_notify(_Lock, _At_thread_exit);
767+ }
768+ template <class _Ty2 >
769+ void _ Emplace_result(_ Ty2&& _ Val) {
770+ // TRANSITION, incorrectly assigns _ Result when _ Ty is default constructible
771+ if constexpr (is_default_constructible_v<_ Ty>) {
772+ _ Result = _ STD forward<_ Ty2>(_ Val); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
773+ } else {
774+ ::new (static_cast<void* >(_ STD addressof(_ Result._ Held_value))) _ Ty(_ STD forward<_ Ty2>(_ Val));
775+ _ Has_stored_result = true;
776+ }
777+ }
778+ ```
779+
780+ ## 总结
781+
782+ 好了,到此也就可以了。
783+
784+ 你不会期待我们将每一个成员函数都分析一遍吧?首先是没有必要,其次是篇幅限制。
785+
786+ `std::future` 的继承关系让人感到头疼,但是如果耐心的看了一遍,全部搞明白了继承关系, `std::async` 如何创建的 `std::future` 也就没有问题了。
787+
788+ 其实各位不用着急完全理解,可以慢慢看,至少有许多的显著的信息,比如:
789+
790+ 1. `sttd::future` 的很多部分,如 `get()` 成员函数实现中,实际使用了虚函数。
791+ 2. `std::async` 创建 `std::future` 对象中,内部其实也有父类指针指向子类对象,以及多态调用。
792+ 3. `std::async` 的非延迟执行策略,使用到了自家的 PPL 库。
793+ 4. 微软的 `std::async` 策略实现并不符合标准,不区分 `launch::async | launch::deferred` 和 `launch::async`。
794+ 5. `std::future` 内部使用到了互斥量、条件变量、异常指针等设施。
0 commit comments