std::future的实现分析

std::future类模板的定义

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

future继承自_State_manager,future没有任何数据成员,其内存布局与父类一模一样,为用户提供的公共接口函数实质也是通过继承 _State_manager的函数实现。

1. _State_manager分析

_State_manager类模板用来管理(可能不存在的)关联异步状态对象

私有数据成员:

private:
_Associated_state<_Ty> *_Assoc_state;
bool _Get_only_once;
  • _Assoc_state:指向关联的异步状态对象

    _Associated_state是一个线程安全的类,内部通过互斥锁和条件变量实现共享数据的安全同步。

    这个类是为c++11高级同步方式(promise/packeged_task/async)提供了底层支持。

  • _Get_only_once:标识关联的状态是否只能提取一次(std::future)还是多次(std::shared_future)

构造与赋值函数

//默认构造函数,无关联的异步状态,默认允许多次提取关联状态
_State_manager()
: _Assoc_state(nullptr)
{   
    _Get_only_once = false;
}

//通过关联异步状态对象构造
_State_manager(_Associated_state<_Ty> *_New_state, bool _Get_once)
: _Assoc_state(_New_state)
{   
    _Get_only_once = _Get_once;
}
//拷贝构造
_State_manager(const _State_manager& _Other, bool _Get_once = false)
: _Assoc_state(nullptr)
{   
    _Copy_from(_Other);
    _Get_only_once = _Get_once;
}
//移动构造
_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);
}
//移动赋值
_State_manager& operator=(_State_manager&& _Other)
{   
    _Move_from(_Other);
    return (*this);
}

拷贝和移动的真正实现:

//拷贝_State_manager
void _Copy_from(const _State_manager& _Other)
{   //防止自我拷贝、赋值
    if (this != _STD addressof(_Other))
    {   
        //先判断是否有引用的关联状态
        if (_Assoc_state)
            _Assoc_state->_Release();
        if (_Other._Assoc_state == nullptr)
            _Assoc_state = nullptr;
        else
        {   //增加_Assoc_state对象的引用计数
            _Other._Assoc_state->_Retain(); 
            //拷贝数据成员
            _Assoc_state = _Other._Assoc_state;
            _Get_only_once = _Other._Get_only_once;
        }
    }
}

//移动_State_manager
void _Move_from(_State_manager& _Other)
{   
    //防止自我移动、赋值
    if (this != _STD addressof(_Other))
    {   
        //先释放*this的关联状态
        if (_Assoc_state)
            _Assoc_state->_Release();
        //将other的关联状态转移到*this
        _Assoc_state = _Other._Assoc_state;
        _Other._Assoc_state = nullptr;
        _Get_only_once = _Other._Get_only_once;
    }
}
  • 不管是从other拷贝还是移动,都要首先避免自我拷贝、移动
  • 不管是从other拷贝还是移动,都要判断是否有引用关联对象

析构:

//如果有关联的异步对象,则释放
~_State_manager() noexcept
{   
    if (_Assoc_state != nullptr)
        _Assoc_state->_Release();
}

状态:

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

_State_manager状态是否有效必须符合:

  • 指向关联状态的指针有效
  • 关联状态的值——即异步结果——是否被提取
    1. 如果是std::future,则关联状态只能被提取一次
    2. 如果是std::shared_future,则与关联状态是否被提取无关

等待异步结果发生:

这些wait系列函数是future和shared_future对应的wait系列函数的真正实现。

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

提取和设置异步状态结果

//提取关联状态的结果---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));
}

//设置关联状态的结果---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类定义不可复制异步返回对象(_State_manager管理(可能不存在的)关联异步状态对象)

future无任何私有数据成员,其提供的接口都是调用父类 _State_manager的函数实现。

构造、赋值、析构

using _Mybase = _State_manager<_Ty>;
...
//默认构造
future() noexcept
    {   
    }
//移动构造--调用父类的移动构造
future(future&& _Other) noexcept
    : _Mybase(_STD move(_Other), true)//future is-a _State_manager
    {   
    }
//移动赋值--调用父类的移动赋值
future& operator=(future&& _Right) noexcept
{   
    _Mybase::operator=(_STD move(_Right));
    return (*this);
}

//通过_State_manager构造future
future(const _Mybase& _State, _Nil)
    : _Mybase(_State, true)
    {   
    }

//只析构future本身,不会销毁其父类
~future() noexcept
    {   //因为future没有数据成员,什么也不做
    }

//显示定义future不可拷贝
future(const future&) = delete;
future& operator=(const future&) = delete;

提取关联的异步状态

_Ty get()
{   
    //移动构造局部future,掏空*this
    future _Local{_STD move(*this)};
    return (_STD move(_Local._Get_value()));
}

通过std::future::get()提取关联的异步状态结果后,future实例因为以移动构造的方式构造局部future对象(get返回后销毁)之后,将不再可用(future::valid()返回false),并且不能通过future::get()再次提取异步状态结果.

——这并不代表异步状态不再存在,只是无法通过future::get()一次以上

转换为shared_future

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

share()实质是通过future对象构造了shared_future实例。

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

之后future实例的将不再有效,异步状态的访问权转移到新创建的shared_future.

3. std::shared_future分析

shared_future类的定义

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

shared_future类定义可复制异步返回对象,与future一样继承自 State_manager,shared_future也没有任何数据成员,其内存布局与父类一模一样,为用户提供的公共接口函数实质也是通过_State_manager的函数实现.

构造、赋值、析构

shared_future() noexcept
        {   // construct
        }
    
    //支持拷贝
    shared_future(const shared_future& _Other) noexcept
        : _Mybase(_Other)
        {   
        }
    //支持拷贝复制
    shared_future& operator=(const shared_future& _Right) noexcept
        {   
        _Mybase::operator=(_Right);
        return (*this);
        }
    
    //从future构造
    shared_future(future<_Ty>&& _Other) noexcept
        : _Mybase(_STD forward<_Mybase>(_Other))
        {   // construct from rvalue future object
        }
    
    //支持移动构造
    shared_future(shared_future&& _Other) noexcept
        : _Mybase(_STD move(_Other))    //触发_Mybase移动构造
        {   
        }
    //支持移动赋值
    shared_future& operator=(shared_future&& _Right) noexcept
        {   
        _Mybase::operator=(_STD move(_Right));  ////触发_Mybase移动赋值
        return (*this);
        }

    ~shared_future() noexcept
        {   // destroy
        }
  • 多个shared_future对象可以关联同一个异步状态对象,故shared_future是可拷贝的
  • 不管是构造还是赋值,主要是对父类_State_manager的拷贝、移动、赋值
  • 前面提过_Get_only_once,除非在构造State_manager时显示设置为true,否则在State_manager实例中默认为false——即异步状态对象可以被多次提取。在构造shared_future时,并未显示的设置 _Get_only_once为ture,故可以通过shared_future多次提取关联的异步状态。

提取关联的异步状态

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

与std::future::get()不同的时,调用shared_future::get()不会导致

  • shared_future不在有效——因为并未移动shared_future
  • 多次get()将报错——因为_Get_only_once为false

4 线程安全性

  • 代表异步状态结果的类_Associated_state本身是线程安全的(内部通过互斥锁和条件变量实现共享数据的安全同步)
  • future、shared_future本身非线程安全,这是因为其父类_State_manager并非线程安全的。如果多个线程同时操作同一个future、shared_future,比如拷贝、析构、赋值,在没有额外的同步保护机制下,将引发数据竞争。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341