中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

深圳汽車網(wǎng)站建設(shè)win7優(yōu)化教程

深圳汽車網(wǎng)站建設(shè),win7優(yōu)化教程,做網(wǎng)站屬于什么學(xué)科,下載的html模板怎么用文章目錄 八、day81. std::async2. std::future2.1 wait()2.2 get() 八、day8 之前說過,std::async內(nèi)部的處理邏輯和std::thread相似,而且std::async和std::future有密不可分的聯(lián)系。今天,通過對(duì)std::async和std::future源碼進(jìn)行解析&#x…

文章目錄

  • 八、day8
  • 1. std::async
  • 2. std::future
    • 2.1 wait()
    • 2.2 get()

八、day8

之前說過,std::async內(nèi)部的處理邏輯和std::thread相似,而且std::asyncstd::future有密不可分的聯(lián)系。今天,通過對(duì)std::asyncstd::future源碼進(jìn)行解析,了解二者的處理邏輯和關(guān)系。

源碼均基于 MSVC 實(shí)現(xiàn)

參考:

  1. 博主戀戀風(fēng)辰的個(gè)人博客
  2. up主mq白cpp的個(gè)人倉庫

1. std::async

std::async有兩種重載實(shí)現(xiàn):

template <class _Fty, class... _ArgTypes>
_NODISCARD future<_Invoke_result_t<decay_t<_Fty>, decay_t<_ArgTypes>...>> async(launch _Policy, _Fty&& _Fnarg, _ArgTypes&&... _Args) {// manages a callable object launched with supplied policyusing _Ret   = _Invoke_result_t<decay_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_t<decay_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)...);
}

第一種重載需要顯式指定啟動(dòng)策略,也就是我們之前說的std::launch::async、std::launch::deferredstd::launch::async | std::launch::deferred;第二種重載在使用默認(rèn)策略時(shí)會(huì)被調(diào)用(也就是只傳遞可調(diào)用對(duì)象和參數(shù)而不傳遞啟動(dòng)策略),在內(nèi)部會(huì)調(diào)用第一種重載并傳入一個(gè)std::launch::async | std::launch::deferred策略,并將參數(shù)全部轉(zhuǎn)發(fā)。

我們只需要著重關(guān)注第一種重載即可:

  1. 模板參數(shù)和函數(shù)體外部信息:

    • _Fty:可調(diào)用對(duì)象的類型
    • _ArgTypes:可調(diào)用對(duì)象所需的參數(shù)類型
    • _NODISCARD:宏,用于標(biāo)記該函數(shù)的返回值不應(yīng)被忽略
  2. 返回類型:

    future<_Invoke_result_t<decay_t<_Fty>, decay_t<_ArgTypes>...>>
    

    其實(shí)就是返回一個(gè) std::future 對(duì)象,_Invoke_result_t<decay_t<_Fty>, decay_t<_ArgTypes>...>std::invoke對(duì)給定的可調(diào)用對(duì)象 _Fnarg 和參數(shù) _Args... 執(zhí)行后返回的類型,其實(shí)也就是通過 _Invoke_result_t_Fty_ArgTypes... 中推導(dǎo)出的返回類型。

    我們之前在thread源碼解析中說過std::invoke內(nèi)部其實(shí)是調(diào)用_Call函數(shù),_Call函數(shù)負(fù)責(zé)提供參數(shù)并調(diào)用傳入的可調(diào)用對(duì)象。

    我們可以把 _Invoke_result_t 看作是一個(gè)對(duì) std::invoke 的結(jié)果類型的封裝,std::invoke 是一個(gè)工具,可以調(diào)用可調(diào)用對(duì)象并返回其結(jié)果。_Invoke_result_t 提供了一種方式來“推導(dǎo)”出這個(gè)結(jié)果類型。

    這個(gè)類型萃取工具通常長這樣(簡化版):

    template <typename _Callable, typename... _Args>
    struct _Invoke_result_t {using type = decltype(std::invoke(std::declval<_Callable>(), std::declval<_Args>()...));
    };
    

    上述代碼通過 std::invoke 來推導(dǎo)(decltype_Callable(即可調(diào)用對(duì)象)在給定參數(shù) _Args... 上執(zhí)行后的返回類型。換句話說,_Invoke_result_t<_Fty, _ArgTypes...>type 成員類型就是可調(diào)用對(duì)象在調(diào)用后的返回類型。

    值得注意的是,所有類型在傳遞前都進(jìn)行了 decay 處理,也就是將cv和const修飾符去掉,默認(rèn)按值傳遞與 std::thread 的行為一致。

  3. 形參:

    future<_Ret> async(launch _Policy, _Fty&& _Fnarg, _ArgTypes&&... _Args) {}
    
    • launch _Policy: 表示任務(wù)的執(zhí)行策略,可以是 launch::async(表示異步執(zhí)行)或 launch::deferred(表示延遲執(zhí)行),或者std::launch::async | std::launch::deferred
    • _Fty&& _Fnarg: 可調(diào)用對(duì)象,通過完美轉(zhuǎn)發(fā)機(jī)制將其轉(zhuǎn)發(fā)給實(shí)際的異步任務(wù)
    • _ArgTypes&&... _Args: 調(diào)用該可調(diào)用對(duì)象時(shí)所需的參數(shù),同樣通過完美轉(zhuǎn)發(fā)機(jī)制進(jìn)行轉(zhuǎn)發(fā)
  4. _Ret_Ptype

    • _Ret就算我們?cè)诜祷仡愋椭姓f到的_Invoke_result_t<decay_t<_Fty>, decay_t<_ArgTypes>...>,表示可調(diào)用對(duì)象的返回類型;

    • using _Ptype = typename _P_arg_type<_Ret>::type_Ptype 的定義在大多數(shù)情況下和 _Ret 是相同的,類模板 _P_arg_type 只是為了處理引用類型以及 void 的情況,參見 _P_arg_type 的實(shí)現(xiàn):

      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_type<void> { // type for functions returning voidusing type = int;
      };
      

      為什么需要 _Ptype

      在異步任務(wù)的實(shí)現(xiàn)中,std::promise 是用于將結(jié)果與 std::future 綁定的對(duì)象。std::promise 的模板參數(shù)通常是可調(diào)用對(duì)象返回值的類型。在 std::async 函數(shù)中,我們需要?jiǎng)?chuàng)建一個(gè) std::promise 對(duì)象來存儲(chǔ)任務(wù)的結(jié)果,因此我們需要計(jì)算出正確的承諾類型(promise type)。也就是說,定義 _Ptype 是為了配合后面 _Promise 的使用,確保任務(wù)的結(jié)果可以通過 std::future 獲取。

      • _Ret 是任務(wù)返回的類型(由 _Invoke_result_t 推導(dǎo)出)。

      • _Ptype 就是這個(gè)返回類型的承諾類型。也就是說,**_Ptypestd::promise 的模板參數(shù)類型,**表示這個(gè)任務(wù)結(jié)果的類型。

      _Ptype 的定義在大多數(shù)情況下和 _Ret 是相同的,都是可調(diào)用對(duì)象返回值的類型。

  5. _Promise<_Ptype> _Pr:創(chuàng)建一個(gè) std::promise 對(duì)象 _Pr,其類型為 _Ptype,表示與異步任務(wù)的結(jié)果相關(guān)聯(lián)的承諾(promise)。_Promise類型我們之前講過,這里就不在敘述它的作用,關(guān)鍵還在于其存儲(chǔ)的數(shù)據(jù)成員:

    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;
    };
    

    注意:_Promisestd::promise 并不是同一個(gè)模板類,_Promise是為了提供對(duì) std::promise 的進(jìn)一步定制,并不是std::primse本身。std::primise模板類的私有成員是通過_Promise聲明的,即

    // std::primise 的私有成員
    private:_Promise<_Ty*> _MyPromise;
    

    _Promise 類模板是對(duì)_State_manager類模板的包裝,并增加了一個(gè)表示狀態(tài)的私有成員 _Future_retrieved

    private:_State_manager<_Ty> _State;bool _Future_retrieved;
    

    狀態(tài)成員用于跟蹤 _Promise 是否已經(jīng)調(diào)用過 _Get_state_for_future() 成員函數(shù);它默認(rèn)為 false,在第一次調(diào)用 _Get_state_for_future() 成員函數(shù)時(shí)被置為 true,如果二次調(diào)用,就會(huì)拋出future_errc::future_already_retrieved異常。

    _Promise 的構(gòu)造函數(shù)接受的不是_State_manager 類型的對(duì)象,而是_Associated_state 類型的指針,用來初始化數(shù)據(jù)成員 _State。

    _Promise(_Associated_state<_Ty>* _State_ptr) : _State(_State_ptr, false), _Future_retrieved(false) {}
    

    這是因?yàn)閷?shí)際上_State_manager類型只有兩個(gè)私有成員:Associated_state指針,以及一個(gè)狀態(tài)成員:

    private:_Associated_state<_Ty>* _Assoc_state;bool _Get_only_once;
    

    可以簡單理解為 _State_manager 是對(duì) Associated_state 的包裝,其中的大部分接口實(shí)際上是調(diào)用 _Assoc_state 的成員函數(shù)(你們可以去_State_manager的實(shí)現(xiàn)源碼中查閱,大部分接口其實(shí)都是通過調(diào)用_Assoc_state實(shí)現(xiàn)的)。

    所以在解析std::async源碼之前,我們必須對(duì)Associated_state有一個(gè)清晰的了解:

    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模板類主要的成員變量(我沒有全部列上去,只列了主要的),其中,最為重要的三個(gè)變量是:異常指針、互斥量條件變量

    其實(shí),_Associated_state 模板類負(fù)責(zé)管理異步任務(wù)的狀態(tài),包括結(jié)果的存儲(chǔ)、異常的處理以及任務(wù)完成的通知。它是實(shí)現(xiàn) std::futurestd::promise 的核心組件之一,通過 _State_manager_Promise 類模板對(duì)其進(jìn)行封裝和管理,提供更高級(jí)別的接口和功能。

    在這里插入圖片描述

    _Promise、_State_manager、_Associated_state 之間的包含關(guān)系如上述結(jié)構(gòu)所示。

  6. 初始化 _Promise 對(duì)象:

    _Promise<_Ptype> _Pr(_Get_associated_state<_Ret>(_Policy, _Fake_no_copy_callable_adapter<_Fty, _ArgTypes...>(_STD forward<_Fty>(_Fnarg), _STD forward<_ArgTypes>(_Args)...))
    );
    

    這是一個(gè)函數(shù)調(diào)用,將我們 std::async 的參數(shù)全部轉(zhuǎn)發(fā)給它。

    1. 首先將參數(shù) _Fnarg (可調(diào)用對(duì)象)和 _Args...(傳入可調(diào)用對(duì)象的參數(shù)包) 通過 std::forward 轉(zhuǎn)發(fā)給 _Fake_no_copy_callable_adapter。
    2. 然后,_Fake_no_copy_callable_adapter 創(chuàng)建一個(gè)可調(diào)用對(duì)象(函數(shù)適配器)。
    3. 接著,適配器和指定的啟動(dòng)策略被傳遞給 _Get_associated_state 函數(shù),目的是獲取與異步操作相關(guān)的狀態(tài)。
    4. 最終,_Get_associated_state 返回一個(gè)與異步操作相關(guān)的狀態(tài),并將其傳遞給 _Pr,這將會(huì)返回一個(gè) _Promise<_Ptype>,代表一個(gè)異步操作的結(jié)果。

    _Get_associated_state函數(shù)根據(jù)啟動(dòng)模式(_Policy,有三種)來決定創(chuàng)建的異步任務(wù)狀態(tài)對(duì)象類型:

    template <class _Ret, class _Fty>
    _Associated_state<typename _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 函數(shù)返回一個(gè) _Associated_state 指針( _Associated_state 可用于初始化_State_manager,_State_manager可用于初始化_Promise),該指針指向一個(gè)新的 _Deferred_async_state_Task_async_state 對(duì)象。這兩個(gè)類分別對(duì)應(yīng)于異步任務(wù)的兩種不同執(zhí)行策略:延遲執(zhí)行異步執(zhí)行。

    這段代碼也很好的說明,launch::async | launch::deferredlaunch::async 的行為是相同的,都會(huì)創(chuàng)建新線程異步執(zhí)行任務(wù),只不過前者會(huì)自行判斷系統(tǒng)資源來抉擇。


    _Task_async_state_Deferred_async_state 都繼承自 _Packaged_state,其用于異步執(zhí)行任務(wù)。它們的構(gòu)造函數(shù)都接受一個(gè)函數(shù)對(duì)象,并將其轉(zhuǎn)發(fā)給基類 _Packaged_state 的構(gòu)造函數(shù)。

    // _Task_async_state 的構(gòu)造函數(shù)
    template <class _Rx>
    class _Task_async_state : public _Packaged_state<_Rx()>
    // _Deferred_async_state 的構(gòu)造函數(shù)
    template <class _Rx>
    class _Deferred_async_state : public _Packaged_state<_Rx()>
    

    _Packaged_state 類型只有一個(gè)數(shù)據(jù)成員 :std::function 類型的對(duì)象 _Fn,它用來存儲(chǔ)需要執(zhí)行的異步任務(wù),而它又繼承自 _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的可調(diào)用對(duì)象。同時(shí),_Packaged_state繼承自_Associated_state_Associated_state_Primise類中成員_State的最基本組成對(duì)象,基本所有的接口都是通過調(diào)用_Associated_state 的函數(shù)實(shí)現(xiàn)的。

    _Task_async_state_Deferred_async_state 的構(gòu)造函數(shù)如下:

    // _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有一個(gè)數(shù)據(jù)成員_Task用于從線程池中獲取線程,并執(zhí)行可調(diào)用對(duì)象:

    private:::Concurrency::task<void> _Task;
    

    _Task_async_state 的實(shí)現(xiàn)使用了微軟實(shí)現(xiàn)的并行模式庫(PPL)。簡而言之, launch::async 策略并不是單純的創(chuàng)建線程讓任務(wù)執(zhí)行,而是使用了微軟的 ::Concurrency::create_task ,它從線程池中獲取線程并執(zhí)行任務(wù)返回包裝對(duì)象。

    this->_Call_immediate()是調(diào)用 _Task_async_state 的父類 _Packaged_state 的成員函數(shù) _Call_immediate.

    _Packaged_state有三個(gè)版本,自然_Call_immediate也有三種版本,用于處理可調(diào)用對(duì)象返回類型的三種情況

    // 返回普通類型
    // class _Packaged_state<void(_ArgTypes...)>
    void _Call_immediate(_ArgTypes... _Args) {_TRY_BEGIN// 調(diào)用函數(shù)對(duì)象并捕獲異常 傳遞返回值this->_Set_value(_Fn(_STD forward<_ArgTypes>(_Args)...), false);_CATCH_ALL// 函數(shù)對(duì)象拋出異常就記錄this->_Set_exception(_STD current_exception(), false);_CATCH_END
    }// 返回引用類型
    // class _Packaged_state<_Ret&(_ArgTypes...)>
    void _Call_immediate(_ArgTypes... _Args) {_TRY_BEGIN// 調(diào)用函數(shù)對(duì)象并捕獲異常 傳遞返回值的地址this->_Set_value(_STD addressof(_Fn(_STD forward<_ArgTypes>(_Args)...)), false);_CATCH_ALL// 函數(shù)對(duì)象拋出異常就記錄this->_Set_exception(_STD current_exception(), false);_CATCH_END
    }// 返回void類型
    // class _Packaged_state<void(_ArgTypes...)>
    void _Call_immediate(_ArgTypes... _Args) { _TRY_BEGIN// 調(diào)用函數(shù)對(duì)象并捕獲異常 因?yàn)榉祷?void 不獲取返回值 而是直接 _Set_value 傳遞一個(gè) 1_Fn(_STD forward<_ArgTypes>(_Args)...);this->_Set_value(1, false);_CATCH_ALL// 函數(shù)對(duì)象拋出異常就記錄this->_Set_exception(_STD current_exception(), false);_CATCH_END
    }
    

    _Fn(_STD forward<_ArgTypes>(_Args)...表示執(zhí)行可調(diào)用對(duì)象,this->_Set_value(_Fn(_STD forward<_ArgTypes>(_Args)...)表示將可調(diào)用對(duì)象的返回值傳入給_Set_value,其他兩個(gè)函數(shù)也是類似的處理過程。

    _TRY_BEGIN、_CATCH_ALL_CATCH_END類似try-catch塊。當(dāng) _Fn 函數(shù)對(duì)象拋出異常時(shí),控制流會(huì)跳轉(zhuǎn)到 _CATCH_ALL 代碼塊;this->_Set_exception用來記錄當(dāng)前捕獲的異常;_CATCH_END 標(biāo)識(shí)異常處理的結(jié)束;因?yàn)榉祷仡愋蜑?code>void 表示不獲取返回值,所以這里通過_Set_value 傳遞一個(gè) 1(表示正確執(zhí)行的狀態(tài))。所有的返回值均傳入給_Set_value

    簡而言之,就是把返回引用類型的可調(diào)用對(duì)象返回值的引用獲取地址傳遞給 _Set_value,把返回 void 類型的可調(diào)用對(duì)象傳遞一個(gè) 1 (表示正確執(zhí)行的狀態(tài))給 _Set_value。

    _Set_value、_set_exception函數(shù)來自_Packaged_state模板類的父類_Associated_state,通過這兩個(gè)函數(shù),傳遞的可調(diào)用對(duì)象執(zhí)行結(jié)果,以及可能的異常,并將結(jié)果或異常存儲(chǔ)在 _Associated_state。

    b. _Deferred_async_state

    _Deferred_async_state不會(huì)從線程池中獲取一個(gè)新線程,然后再新線程中執(zhí)行任務(wù),而是當(dāng)前線程調(diào)用future的get或者wait函數(shù)時(shí),在當(dāng)前線程同步執(zhí)行。但它同樣調(diào)用 _Call_immediate 函數(shù)執(zhí)行存儲(chǔ)的可調(diào)用對(duì)象,它有一個(gè) _Run_deferred_function 函數(shù):

    void _Run_deferred_function(unique_lock<mutex>& _Lock) override { // run the deferred function_Lock.unlock();_Packaged_state<_Rx()>::_Call_immediate();_Lock.lock();
    }
    

    然后通過 _Call_immediate調(diào)用可調(diào)用對(duì)象并通過函數(shù)_Set_value_set_exception存儲(chǔ)可調(diào)用對(duì)象返回結(jié)果或者異常至_Associated_state。

  7. 返回 std::future

    return future<_Ret>(_Pr._Get_state_for_future(), _Nil());
    

    _Ret在前面說了,其實(shí)就是可調(diào)用對(duì)象返回值的類型。

    傳給future構(gòu)造函數(shù)的參數(shù)之一是:_Pr._Get_state_for_future(),調(diào)用上面構(gòu)造的_Promise的成員函數(shù)_Get_state_for_future,該函數(shù)用于返回_Promise類的私有成員變量_State。

    _Get_state_for_future函數(shù)的實(shí)現(xiàn)如下:

    _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;
    }
    

    其實(shí)就是調(diào)用_State的成員函數(shù)valid()檢查狀態(tài)(是否有錯(cuò)),然后判斷future是否提前返回可調(diào)用對(duì)象的返回值(如果是,代表future的get被調(diào)用,拋出異常);最后,返回_State。

2. std::future

我們首先從一個(gè)最簡單的std::async示例開始:

std::future<int> future = std::async([] { return 0; });
future.get();

我們從之前的學(xué)習(xí)中了解到,future.get()就是從future中獲取可調(diào)用對(duì)象的返回結(jié)果。唯一的問題是:future.get() 內(nèi)部執(zhí)行了什么流程?首先從future的實(shí)現(xiàn)開始:

_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 future<T> 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類又有一個(gè)_Associated_state<_Ty>*類型的私有成員_State,而_State_manager的接口實(shí)現(xiàn)大部分是通過調(diào)用_Associated_state 的成員函數(shù)實(shí)現(xiàn)的。關(guān)系如下:

在這里插入圖片描述

2.1 wait()

但你可能發(fā)現(xiàn)一個(gè)問題,future類怎么沒有wait()成員函數(shù)????其實(shí),wait()函數(shù)繼承自父類_State_manager。

void wait() const { // wait for signalif (!valid()) {_Throw_future_error2(future_errc::no_state);}_Assoc_state->_Wait();
}

_State_manager類的wait()其實(shí)是通過調(diào)用_Associated_state的接口實(shí)現(xiàn)的,所以說,_Associated_statestd::asyncstd::future中是非常核心的。

virtual void _Wait() { // wait for signalunique_lock<mutex> _Lock(_Mtx);_Maybe_run_deferred_function(_Lock);while (!_Ready) {_Cond.wait(_Lock);}
}

_Associated_statewait()函數(shù)通過unique_lock保護(hù)共享數(shù)據(jù),然后調(diào)用_Maybe_run_deferred_function執(zhí)行可調(diào)用對(duì)象,直至調(diào)用結(jié)束。

void _Maybe_run_deferred_function(unique_lock<mutex>& _Lock) { // run a deferred function if not already doneif (!_Running) { // run the function_Running = true;_Run_deferred_function(_Lock);}
}

_Maybe_run_deferred_function其實(shí)就是通過調(diào)用_Run_deferred_function來調(diào)用_Call_immediate(),我們?cè)?code>async源碼中學(xué)習(xí)過_Run_deferred_function和`_Call_immediate()。

void _Run_deferred_function(unique_lock<mutex>& _Lock) override { // run the deferred function_Lock.unlock();_Packaged_state<_Rx()>::_Call_immediate();_Lock.lock();
}

_Wait 函數(shù)中調(diào)用 _Maybe_run_deferred_function 是為了確保延遲執(zhí)行(launch::deferred)的任務(wù)能夠在等待前被啟動(dòng)并執(zhí)行完畢。這樣,在調(diào)用 wait 時(shí)可以正確地等待任務(wù)完成。

因?yàn)橹挥?code>std::launch::deferred才是當(dāng)調(diào)用future.get或者wait時(shí)才會(huì)執(zhí)行_Call_immediate(),其他兩種啟動(dòng)策略在大部分情況下都是直接執(zhí)行,通過future.get獲得結(jié)果。所以我們必須保證在調(diào)用wait函數(shù)時(shí),執(zhí)行std::launch::deferred策略的任務(wù)被執(zhí)行,而其他兩種啟動(dòng)策略早已經(jīng)執(zhí)行任務(wù),無需再調(diào)用_Call_immediate()。所以在_Maybe_run_deferred_function函數(shù)中,有下面一段,判斷任務(wù)是否以及執(zhí)行,如果被執(zhí)行,那么久就不調(diào)用_Call_immediate,反之調(diào)用。

    if (!_Running) { // run the function_Running = true;_Run_deferred_function(_Lock);

   while (!_Ready) {_Cond.wait(_Lock);}

通過條件變量掛起當(dāng)前線程,等待可調(diào)用對(duì)象執(zhí)行完畢。在等待期間,當(dāng)前線程釋放持有的鎖,保證其他線程再次期間可以訪問到共享資源,待當(dāng)前線程被喚醒后,重新持有鎖。其主要作用是:

  1. 避免虛假喚醒:
    • 條件變量的 wait 函數(shù)在被喚醒后,會(huì)重新檢查條件(即 _Ready 是否為 true),確保只有在條件滿足時(shí)才會(huì)繼續(xù)執(zhí)行。這防止了由于虛假喚醒導(dǎo)致的錯(cuò)誤行為。
  2. 等待 launch::async 的任務(wù)在其它線程執(zhí)行完畢:
    • 對(duì)于 launch::async 模式的任務(wù),這段代碼確保當(dāng)前線程會(huì)等待任務(wù)在另一個(gè)線程中執(zhí)行完畢,并接收到任務(wù)完成的信號(hào)。只有當(dāng)任務(wù)完成并設(shè)置 _Readytrue 后,條件變量才會(huì)被通知,從而結(jié)束等待。

這樣,當(dāng)調(diào)用 wait 函數(shù)時(shí),可以保證無論任務(wù)是 launch::deferred 還是 launch::async 模式,當(dāng)前線程都會(huì)正確地等待任務(wù)的完成信號(hào),然后繼續(xù)執(zhí)行。


std::future 其實(shí)還有兩種特化,不過整體大差不差。

template <class _Ty>
class future<_Ty&> : public _State_manager<_Ty*>
template <>
class future<void> : public _State_manager<int>

也就是對(duì)返回類型為引用和 void 的情況了。其實(shí)先前已經(jīng)聊過很多次了,無非就是內(nèi)部的返回引用實(shí)際按指針操作,返回 void,那么也得給個(gè) 1,表示正常運(yùn)行的狀態(tài)。類似于前面 _Call_immediate 的實(shí)現(xiàn)。

2.2 get()

get()函數(shù)是future的成員函數(shù),而沒有繼承父類_State_manager

// std::future<void>
void get() {// block until ready then return or throw the stored exceptionfuture _Local{_STD move(*this)};_Local._Get_value();
}
// std::future<T>
_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::future<T&>
_Ty& get() {// block until ready then return the stored result or throw the stored exceptionfuture _Local{_STD move(*this)};return *_Local._Get_value();
}

因?yàn)?code>future有三種特化,所以get()函數(shù)也有三種特化。它們將當(dāng)前future對(duì)象的指針通過std::move轉(zhuǎn)移給類型為future的局部變量_Local(轉(zhuǎn)移后,原本的future對(duì)象便失去了所有權(quán))。然后,局部變量_Local調(diào)用成員函數(shù)_Get_value(),并將結(jié)果返回。

注意:局部對(duì)象 _Local 在函數(shù)結(jié)束時(shí)析構(gòu)。這意味著當(dāng)前對(duì)象(*this)失去共享狀態(tài),并且狀態(tài)被完全銷毀。

_Get_value() 函數(shù)的實(shí)現(xiàn)如下:

_Ty& _Get_value() const {if (!valid()) {_Throw_future_error2(future_errc::no_state);}return _Assoc_state->_Get_value(_Get_only_once);
}

future.valid() 成員函數(shù)檢查 future 當(dāng)前是否關(guān)聯(lián)共享狀態(tài),即是否當(dāng)前關(guān)聯(lián)任務(wù)。如果還未關(guān)聯(lián),或者任務(wù)已經(jīng)執(zhí)行完(調(diào)用了 get()、set()),都會(huì)返回 false。

  • 首先,通過valid()判斷當(dāng)前future對(duì)象是否關(guān)聯(lián)共享狀態(tài),如果沒,拋出異常。
  • 最后,調(diào)用 _Assoc_state 的成員函數(shù) _Get_value ,傳遞 _Get_only_once 參數(shù),其實(shí)就是代表這個(gè)成員函數(shù)只能調(diào)用一次。

_Assoc_state 的類型是 _Associated_state<_Ty>* ,是一個(gè)指針類型,它實(shí)際會(huì)指向自己的子類對(duì)象,我們?cè)谥v std::async 源碼的時(shí)候提到了,它必然指向 _Deferred_async_state 或者 _Task_async_state

_Assoc_state->_Get_value 這其實(shí)是個(gè)多態(tài)調(diào)用,父類有這個(gè)虛函數(shù):

virtual _Ty& _Get_value(bool _Get_only_once) {unique_lock<mutex> _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 對(duì)其進(jìn)行了重寫,以 launch::async 策略或者std::launch::async | std::launch::deferred策略創(chuàng)建的future,實(shí)際會(huì)調(diào)用 _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 沒有對(duì)其進(jìn)行重寫,直接調(diào)用父類虛函數(shù)。

_Task 就是 ::Concurrency::task<void> _Task;,調(diào)用 wait() 成員函數(shù)確保任務(wù)執(zhí)行完畢。

_Mybase::_Get_value(_Get_only_once) 其實(shí)又是回去調(diào)用父類的虛函數(shù)了。

_Get_value 方法詳解

  1. _Get_value()只能調(diào)用一次

    如果 _Get_only_oncetrue_Retrievedtrue(表示結(jié)果已經(jīng)被檢索過),則拋出 future_already_retrieved 錯(cuò)誤。

  2. 處理異常

    如果在獲取結(jié)果過程中出現(xiàn)了異常,需要重新拋出該異常

  3. 設(shè)置 _Retrievedtrue

    在獲取值之前,設(shè)置 _Retrievedtrue,表示結(jié)果已經(jīng)被檢索過。這樣可以確保 future 對(duì)象不會(huì)被重復(fù)獲取,避免多次調(diào)用 get 時(shí)引發(fā)錯(cuò)誤。

  4. 執(zhí)行延遲函數(shù)

    調(diào)用_Maybe_run_deferred_function來運(yùn)行可能的延遲任務(wù)。在該函數(shù)內(nèi)部,如果任務(wù)已經(jīng)運(yùn)行,那么退出,如果沒運(yùn)行,調(diào)用_Call_immediate()函數(shù)執(zhí)行可調(diào)用對(duì)象。

  5. 等待結(jié)果

    使用條件變量掛起當(dāng)前線程,確保線程同步,即只有當(dāng)異步任務(wù)準(zhǔn)備好返回結(jié)果時(shí),線程才會(huì)繼續(xù)執(zhí)行。

  6. 再次檢查異常

    線程被喚醒將結(jié)果存儲(chǔ)至future對(duì)象中后,再次判斷是否發(fā)生了異常,需要重新拋出異常

  7. 返回結(jié)果

    這部分代碼根據(jù) _Ty 類型的特性決定如何返回結(jié)果:

    • 如果 _Ty 類型是 默認(rèn)可構(gòu)造(即 _Ty 的默認(rèn)構(gòu)造函數(shù)有效),直接返回 _Result
    • 否則,返回 _Result._Held_value

    is_default_constructible_v<_Ty> 是一個(gè) C++17 引入的類型特征,用于檢查類型 _Ty 是否具有默認(rèn)構(gòu)造函數(shù)。

    _Resultfuture 中持有的結(jié)果,而 _Held_value 是存儲(chǔ)在 _Result 中的實(shí)際值。

_Result 是通過執(zhí)行 _Call_immediate 函數(shù),然后 _Call_immediate 再執(zhí)行 _Set_value_Set_value 再執(zhí)行 _Set_value_raw_Set_value_raw再執(zhí)行_Emplace_result并通知線程可以醒來,_Emplace_result 獲取到我們執(zhí)行任務(wù)的返回值的。以 Ty 的偏特化為例:

// _Packaged_state
void _Call_immediate(_ArgTypes... _Args) {_TRY_BEGIN// 調(diào)用函數(shù)對(duì)象并捕獲異常 傳遞返回值this->_Set_value(_Fn(_STD forward<_ArgTypes>(_Args)...), false);_CATCH_ALL// 函數(shù)對(duì)象拋出異常就記錄this->_Set_exception(_STD current_exception(), false);_CATCH_END
}// _Asscoiated_state
void _Set_value(const _Ty& _Val, bool _At_thread_exit) { // store a resultunique_lock<mutex> _Lock(_Mtx);_Set_value_raw(_Val, &_Lock, _At_thread_exit);
}
void _Set_value_raw(const _Ty& _Val, unique_lock<mutex>* _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_cast<void*>(_STD addressof(_Result._Held_value))) _Ty(_STD forward<_Ty2>(_Val));_Has_stored_result = true;}
}
http://m.risenshineclean.com/news/58660.html

相關(guān)文章:

  • 公司設(shè)計(jì)網(wǎng)站建設(shè)合同網(wǎng)站友情鏈接的作用
  • 武漢做網(wǎng)站公司推薦怎樣去推廣自己的網(wǎng)店
  • 網(wǎng)站建設(shè)需要什么格式的圖片推廣軟件賺錢違法嗎
  • 昆明網(wǎng)站制作推薦軟文營銷代理
  • 網(wǎng)站開發(fā)實(shí)用技術(shù) 代碼深圳做seo有哪些公司
  • wordpress站群網(wǎng)絡(luò)推廣是什么
  • 上海做網(wǎng)站的費(fèi)用銷售培訓(xùn)
  • 廣告設(shè)計(jì)需要學(xué)多久蘇州百度 seo
  • 網(wǎng)站開發(fā)月薪多少錢小程序推廣運(yùn)營的公司
  • 蘇州網(wǎng)站運(yùn)營公司淘寶關(guān)鍵詞優(yōu)化怎么弄
  • 做視頻網(wǎng)站對(duì)服務(wù)器要去中央電視臺(tái)一套廣告價(jià)目表
  • 百度蜘蛛如何找網(wǎng)站國內(nèi)設(shè)計(jì)公司前十名
  • 溫州網(wǎng)站設(shè)計(jì)工作室軟件開發(fā)平臺(tái)
  • 網(wǎng)站規(guī)劃總結(jié)武漢本地seo
  • 百度做的網(wǎng)站seo資料網(wǎng)
  • 青島開發(fā)區(qū)網(wǎng)站建設(shè)多少錢百度競價(jià)排名的利與弊
  • 臨沂做網(wǎng)站的公司哪里有武漢網(wǎng)絡(luò)推廣網(wǎng)絡(luò)營銷
  • 無需域名網(wǎng)站建設(shè)競價(jià)什么意思
  • 優(yōu)質(zhì)的外國網(wǎng)站如何推廣app賺錢
  • 學(xué)做日本菜的網(wǎng)站好泉州搜索推廣
  • 山西焦煤集團(tuán)公司網(wǎng)站山東seo推廣
  • 佛山網(wǎng)站建設(shè)公司哪家便宜分銷渠道
  • 機(jī)電網(wǎng)站模板整站優(yōu)化系統(tǒng)
  • 淮安網(wǎng)站建設(shè)公司產(chǎn)品推廣方法有哪些
  • 億唐網(wǎng)不做網(wǎng)站做品牌考試題中國互聯(lián)網(wǎng)公司排名
  • 哪里有專業(yè)做網(wǎng)站國內(nèi)最新新聞事件今天
  • 大學(xué)生做企業(yè)網(wǎng)站東莞關(guān)鍵詞優(yōu)化平臺(tái)
  • 怎么做博客網(wǎng)站上海網(wǎng)絡(luò)seo
  • 網(wǎng)站如何做微信支付寶支付寶支付近期國家新聞
  • 動(dòng)態(tài)網(wǎng)站作業(yè)建網(wǎng)站不花錢免費(fèi)建站