std::future的實(shí)現(xiàn)分析

std::future類模板的定義

template<class _Ty>
class future: public _State_manager<_Ty>
{...}

future繼承自_State_manager,future沒(méi)有任何數(shù)據(jù)成員洽瞬,其內(nèi)存布局與父類一模一樣,為用戶提供的公共接口函數(shù)實(shí)質(zhì)也是通過(guò)繼承 _State_manager的函數(shù)實(shí)現(xiàn)樱蛤。

1. _State_manager分析

_State_manager類模板用來(lái)管理(可能不存在的)關(guān)聯(lián)異步狀態(tài)對(duì)象

私有數(shù)據(jù)成員:

private:
_Associated_state<_Ty> *_Assoc_state;
bool _Get_only_once;
  • _Assoc_state:指向關(guān)聯(lián)的異步狀態(tài)對(duì)象

    _Associated_state是一個(gè)線程安全的類壮莹,內(nèi)部通過(guò)互斥鎖和條件變量實(shí)現(xiàn)共享數(shù)據(jù)的安全同步。

    這個(gè)類是為c++11高級(jí)同步方式(promise/packeged_task/async)提供了底層支持荣德。

  • _Get_only_once:標(biāo)識(shí)關(guān)聯(lián)的狀態(tài)是否只能提取一次(std::future)還是多次(std::shared_future)

構(gòu)造與賦值函數(shù)

//默認(rèn)構(gòu)造函數(shù)闷煤,無(wú)關(guān)聯(lián)的異步狀態(tài),默認(rèn)允許多次提取關(guān)聯(lián)狀態(tài)
_State_manager()
: _Assoc_state(nullptr)
{   
    _Get_only_once = false;
}

//通過(guò)關(guān)聯(lián)異步狀態(tài)對(duì)象構(gòu)造
_State_manager(_Associated_state<_Ty> *_New_state, bool _Get_once)
: _Assoc_state(_New_state)
{   
    _Get_only_once = _Get_once;
}
//拷貝構(gòu)造
_State_manager(const _State_manager& _Other, bool _Get_once = false)
: _Assoc_state(nullptr)
{   
    _Copy_from(_Other);
    _Get_only_once = _Get_once;
}
//移動(dòng)構(gòu)造
_State_manager(_State_manager&& _Other, bool _Get_once = false)
: _Assoc_state(nullptr)
{   
    _Move_from(_Other);
    _Get_only_once = _Get_once;
}
//拷貝賦值
_State_manager& operator=(const _State_manager& _Other)
{   
    _Copy_from(_Other);
    return (*this);
}
//移動(dòng)賦值
_State_manager& operator=(_State_manager&& _Other)
{   
    _Move_from(_Other);
    return (*this);
}

拷貝和移動(dòng)的真正實(shí)現(xiàn):

//拷貝_State_manager
void _Copy_from(const _State_manager& _Other)
{   //防止自我拷貝涮瞻、賦值
    if (this != _STD addressof(_Other))
    {   
        //先判斷是否有引用的關(guān)聯(lián)狀態(tài)
        if (_Assoc_state)
            _Assoc_state->_Release();
        if (_Other._Assoc_state == nullptr)
            _Assoc_state = nullptr;
        else
        {   //增加_Assoc_state對(duì)象的引用計(jì)數(shù)
            _Other._Assoc_state->_Retain(); 
            //拷貝數(shù)據(jù)成員
            _Assoc_state = _Other._Assoc_state;
            _Get_only_once = _Other._Get_only_once;
        }
    }
}

//移動(dòng)_State_manager
void _Move_from(_State_manager& _Other)
{   
    //防止自我移動(dòng)鲤拿、賦值
    if (this != _STD addressof(_Other))
    {   
        //先釋放*this的關(guān)聯(lián)狀態(tài)
        if (_Assoc_state)
            _Assoc_state->_Release();
        //將other的關(guān)聯(lián)狀態(tài)轉(zhuǎn)移到*this
        _Assoc_state = _Other._Assoc_state;
        _Other._Assoc_state = nullptr;
        _Get_only_once = _Other._Get_only_once;
    }
}
  • 不管是從other拷貝還是移動(dòng),都要首先避免自我拷貝署咽、移動(dòng)
  • 不管是從other拷貝還是移動(dòng)近顷,都要判斷是否有引用關(guān)聯(lián)對(duì)象

析構(gòu):

//如果有關(guān)聯(lián)的異步對(duì)象,則釋放
~_State_manager() noexcept
{   
    if (_Assoc_state != nullptr)
        _Assoc_state->_Release();
}

狀態(tài):

_NODISCARD bool valid() const noexcept
{   
    return (_Assoc_state != nullptr
    && !(_Get_only_once && _Assoc_state->_Already_retrieved()));
}

_State_manager狀態(tài)是否有效必須符合:

  • 指向關(guān)聯(lián)狀態(tài)的指針有效
  • 關(guān)聯(lián)狀態(tài)的值——即異步結(jié)果——是否被提取
    1. 如果是std::future,則關(guān)聯(lián)狀態(tài)只能被提取一次
    2. 如果是std::shared_future,則與關(guān)聯(lián)狀態(tài)是否被提取無(wú)關(guān)

等待異步結(jié)果發(fā)生:

這些wait系列函數(shù)是future和shared_future對(duì)應(yīng)的wait系列函數(shù)的真正實(shí)現(xiàn)宁否。

void wait() const
{   // wait for signal
    if (!valid())
        _Throw_future_error(make_error_code(future_errc::no_state));
    _Assoc_state->_Wait();
}

template<class _Rep,
class _Per>
        future_status wait_for(const chrono::duration<_Rep, _Per>& _Rel_time) const
{   // wait for duration
    if (!valid())
        _Throw_future_error(make_error_code(future_errc::no_state));
    return (_Assoc_state->_Wait_for(_Rel_time));
}

template<class _Clock,
class _Dur>
        future_status wait_until(const chrono::time_point<_Clock, _Dur>& _Abs_time) const
{   // wait until time point
    if (!valid())
        _Throw_future_error(make_error_code(future_errc::no_state));
    return (_Assoc_state->_Wait_until(_Abs_time));
}

提取和設(shè)置異步狀態(tài)結(jié)果

//提取關(guān)聯(lián)狀態(tài)的結(jié)果---for future::get()/shared_future::get()
_Ty& _Get_value() const
{   
    if (!valid())
        _Throw_future_error(
        make_error_code(future_errc::no_state));
    return (_Assoc_state->_Get_value(_Get_only_once));
}

//設(shè)置關(guān)聯(lián)狀態(tài)的結(jié)果---for promise::set_value()
void _Set_value(const _Ty& _Val, bool _Defer)
{   
    if (!valid())
        _Throw_future_error(
        make_error_code(future_errc::no_state));
    _Assoc_state->_Set_value(_Val, _Defer);
}

void _Set_value(_Ty&& _Val, bool _Defer)
{   
    if (!valid())
        _Throw_future_error(
        make_error_code(future_errc::no_state));
    _Assoc_state->_Set_value(_STD forward<_Ty>(_Val), _Defer);
}

2. std::future分析

future類定義不可復(fù)制異步返回對(duì)象(_State_manager管理(可能不存在的)關(guān)聯(lián)異步狀態(tài)對(duì)象)

future無(wú)任何私有數(shù)據(jù)成員窒升,其提供的接口都是調(diào)用父類 _State_manager的函數(shù)實(shí)現(xiàn)。

構(gòu)造家淤、賦值异剥、析構(gòu)

using _Mybase = _State_manager<_Ty>;
...
//默認(rèn)構(gòu)造
future() noexcept
    {   
    }
//移動(dòng)構(gòu)造--調(diào)用父類的移動(dòng)構(gòu)造
future(future&& _Other) noexcept
    : _Mybase(_STD move(_Other), true)//future is-a _State_manager
    {   
    }
//移動(dòng)賦值--調(diào)用父類的移動(dòng)賦值
future& operator=(future&& _Right) noexcept
{   
    _Mybase::operator=(_STD move(_Right));
    return (*this);
}

//通過(guò)_State_manager構(gòu)造future
future(const _Mybase& _State, _Nil)
    : _Mybase(_State, true)
    {   
    }

//只析構(gòu)future本身,不會(huì)銷毀其父類
~future() noexcept
    {   //因?yàn)閒uture沒(méi)有數(shù)據(jù)成員絮重,什么也不做
    }

//顯示定義future不可拷貝
future(const future&) = delete;
future& operator=(const future&) = delete;

提取關(guān)聯(lián)的異步狀態(tài)

_Ty get()
{   
    //移動(dòng)構(gòu)造局部future冤寿,掏空*this
    future _Local{_STD move(*this)};
    return (_STD move(_Local._Get_value()));
}

通過(guò)std::future::get()提取關(guān)聯(lián)的異步狀態(tài)結(jié)果后,future實(shí)例因?yàn)橐砸苿?dòng)構(gòu)造的方式構(gòu)造局部future對(duì)象(get返回后銷毀)之后青伤,將不再可用(future::valid()返回false)督怜,并且不能通過(guò)future::get()再次提取異步狀態(tài)結(jié)果.

——這并不代表異步狀態(tài)不再存在,只是無(wú)法通過(guò)future::get()一次以上

轉(zhuǎn)換為shared_future

_NODISCARD shared_future<_Ty> share() noexcept
{   
    return (shared_future<_Ty>(_STD move(*this)));
}

share()實(shí)質(zhì)是通過(guò)future對(duì)象構(gòu)造了shared_future實(shí)例狠角。

shared_future(future<T>&& _Other) noexcept
    : _Mybase(std::forward<_Mybase>(_Other))
    { 
    }

之后future實(shí)例的將不再有效,異步狀態(tài)的訪問(wèn)權(quán)轉(zhuǎn)移到新創(chuàng)建的shared_future.

3. std::shared_future分析

shared_future類的定義

template<class _Ty>
    class shared_future
    : public _State_manager<_Ty>
    {}  

shared_future類定義可復(fù)制異步返回對(duì)象号杠,與future一樣繼承自 State_manager,shared_future也沒(méi)有任何數(shù)據(jù)成員,其內(nèi)存布局與父類一模一樣姨蟋,為用戶提供的公共接口函數(shù)實(shí)質(zhì)也是通過(guò)_State_manager的函數(shù)實(shí)現(xiàn).

構(gòu)造屉凯、賦值、析構(gòu)

shared_future() noexcept
        {   // construct
        }
    
    //支持拷貝
    shared_future(const shared_future& _Other) noexcept
        : _Mybase(_Other)
        {   
        }
    //支持拷貝復(fù)制
    shared_future& operator=(const shared_future& _Right) noexcept
        {   
        _Mybase::operator=(_Right);
        return (*this);
        }
    
    //從future構(gòu)造
    shared_future(future<_Ty>&& _Other) noexcept
        : _Mybase(_STD forward<_Mybase>(_Other))
        {   // construct from rvalue future object
        }
    
    //支持移動(dòng)構(gòu)造
    shared_future(shared_future&& _Other) noexcept
        : _Mybase(_STD move(_Other))    //觸發(fā)_Mybase移動(dòng)構(gòu)造
        {   
        }
    //支持移動(dòng)賦值
    shared_future& operator=(shared_future&& _Right) noexcept
        {   
        _Mybase::operator=(_STD move(_Right));  ////觸發(fā)_Mybase移動(dòng)賦值
        return (*this);
        }

    ~shared_future() noexcept
        {   // destroy
        }
  • 多個(gè)shared_future對(duì)象可以關(guān)聯(lián)同一個(gè)異步狀態(tài)對(duì)象眼溶,故shared_future是可拷貝的
  • 不管是構(gòu)造還是賦值悠砚,主要是對(duì)父類_State_manager的拷貝、移動(dòng)堂飞、賦值
  • 前面提過(guò)_Get_only_once灌旧,除非在構(gòu)造State_manager時(shí)顯示設(shè)置為true,否則在State_manager實(shí)例中默認(rèn)為false——即異步狀態(tài)對(duì)象可以被多次提取绰筛。在構(gòu)造shared_future時(shí)枢泰,并未顯示的設(shè)置 _Get_only_once為ture,故可以通過(guò)shared_future多次提取關(guān)聯(lián)的異步狀態(tài)铝噩。

提取關(guān)聯(lián)的異步狀態(tài)

_Ty& get() const
{   
    return (*this->_Get_value());//_State_manager::_Get_value
}

與std::future::get()不同的時(shí)衡蚂,調(diào)用shared_future::get()不會(huì)導(dǎo)致

  • shared_future不在有效——因?yàn)椴⑽匆苿?dòng)shared_future
  • 多次get()將報(bào)錯(cuò)——因?yàn)開(kāi)Get_only_once為false

4 線程安全性

  • 代表異步狀態(tài)結(jié)果的類_Associated_state本身是線程安全的(內(nèi)部通過(guò)互斥鎖和條件變量實(shí)現(xiàn)共享數(shù)據(jù)的安全同步)
  • future、shared_future本身非線程安全薄榛,這是因?yàn)槠涓割恄State_manager并非線程安全的讳窟。如果多個(gè)線程同時(shí)操作同一個(gè)future、shared_future敞恋,比如拷貝、析構(gòu)谋右、賦值硬猫,在沒(méi)有額外的同步保護(hù)機(jī)制下,將引發(fā)數(shù)據(jù)競(jìng)爭(zhēng)改执。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末啸蜜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子辈挂,更是在濱河造成了極大的恐慌衬横,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件终蒂,死亡現(xiàn)場(chǎng)離奇詭異蜂林,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)拇泣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門(mén)噪叙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人霉翔,你說(shuō)我怎么就攤上這事睁蕾。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵子眶,是天一觀的道長(zhǎng)瀑凝。 經(jīng)常有香客問(wèn)我,道長(zhǎng)臭杰,這世上最難降的妖魔是什么猜丹? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮硅卢,結(jié)果婚禮上射窒,老公的妹妹穿的比我還像新娘。我一直安慰自己将塑,他們只是感情好脉顿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著点寥,像睡著了一般艾疟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上敢辩,一...
    開(kāi)封第一講書(shū)人閱讀 51,763評(píng)論 1 307
  • 那天蔽莱,我揣著相機(jī)與錄音,去河邊找鬼戚长。 笑死盗冷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的同廉。 我是一名探鬼主播仪糖,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼迫肖!你這毒婦竟也來(lái)了锅劝?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蟆湖,失蹤者是張志新(化名)和其女友劉穎故爵,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體隅津,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡诬垂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了饥瓷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片剥纷。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖呢铆,靈堂內(nèi)的尸體忽然破棺而出晦鞋,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布悠垛,位于F島的核電站线定,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏确买。R本人自食惡果不足惜斤讥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望湾趾。 院中可真熱鬧芭商,春花似錦、人聲如沸搀缠。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)艺普。三九已至簸州,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間歧譬,已是汗流浹背岸浑。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瑰步,地道東北人矢洲。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像面氓,于是被迫代替她去往敵國(guó)和親兵钮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355