第27课 “共享状态”及其管理者(std::future/std::shared_future)
一. “共享状态”
(一)“共享状态”对象
1. 用于保存线程函数及其参数、返回值以及新线程状态等信息。该对象通常创建在堆上,由std::async、std::promise和std::package_task等提供(Provider),并交由future/shared_future管理。
2. Provider将计算结果写入“共享状态”对象,而future/shared_future通过get()函数来读取该结果。“共享状态”作为异步结果的传输通道,future可以从中方便地获取线程函数的返回值。
3. “共享状态”内部保存着一个引用计数,当引用计数为0时会通过delete this来销毁自身。
// CLASS TEMPLATE _Associated_state
template <class _Ty>
class _Associated_state { // class for managing associated synchronous state
public:
using _State_type = _Ty;
using _Mydel = _Deleter_base<_Ty>; _Associated_state(_Mydel* _Dp = nullptr)
: _Refs(), // non-atomic initialization
_Exception(), _Retrieved(false), _Ready(false), _Ready_at_thread_exit(false), _Has_stored_result(false),
_Running(false), _Deleter(_Dp) { // construct
// TODO: _Associated_state ctor assumes _Ty is default constructible
} virtual ~_Associated_state() noexcept { // 析构函数:注意并不会阻塞
if (_Has_stored_result && !_Ready) { // registered for release at thread exit
_Cond._Unregister(_Mtx);
}
} void _Retain() { // 增加引用计数
_MT_INCR(_Refs);
} void _Release() { // 减少引用计数,等于0时delete this
if (_MT_DECR(_Refs) == ) {
_Delete_this();
}
} private:
_Atomic_counter_t _Refs; public:
virtual void _Wait() { // wait for signal
unique_lock<mutex> _Lock(_Mtx);
_Maybe_run_deferred_function(_Lock);
while (!_Ready) {
_Cond.wait(_Lock);
}
} struct _Test_ready { // _Associated_state包装类
_Test_ready(const _Associated_state* _St) : _State(_St) { // construct from associated state
} bool operator()() const { // 判断“共享状态”是否就绪
return _State->_Ready != ;
}
const _Associated_state* _State;
}; template <class _Rep, class _Per>
future_status _Wait_for(const chrono::duration<_Rep, _Per>& _Rel_time) { // wait for duration
unique_lock<mutex> _Lock(_Mtx);
if (_Has_deferred_function()) {
return future_status::deferred; //如果是延迟任务,调用waitfor将返回deferred,而不是future_status::ready!
} if (_Cond.wait_for(_Lock, _Rel_time, _Test_ready(this))) {
return future_status::ready; //返回future_status::ready
} return future_status::timeout; //返回超时
} template <class _Clock, class _Dur>
future_status _Wait_until(const chrono::time_point<_Clock, _Dur>& _Abs_time) { // wait until time point
unique_lock<mutex> _Lock(_Mtx);
if (_Has_deferred_function()) {
return future_status::deferred;
} if (_Cond.wait_until(_Lock, _Abs_time, _Test_ready(this))) {
return future_status::ready;
} return future_status::timeout;
} virtual _Ty& _Get_value(bool _Get_only_once) { // return the stored result or throw stored exception
unique_lock<mutex> _Lock(_Mtx);
if (_Get_only_once && _Retrieved) { //_Get_only_once:true表示_Get_value只能调用一次,false表示可重复调用
_Throw_future_error(make_error_code(future_errc::future_already_retrieved));
} if (_Exception) {
_Rethrow_future_exception(_Exception);
} _Retrieved = true; //标记_Get_value()函数己被调用过
_Maybe_run_deferred_function(_Lock);
while (!_Ready) { //如果任务结束,则不再等待。
_Cond.wait(_Lock);
} if (_Exception) {
_Rethrow_future_exception(_Exception);
} return _Result;
} void _Set_value(const _Ty& _Val, bool _At_thread_exit) { // store a result
unique_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 block
if (_Has_stored_result) {
_Throw_future_error(make_error_code(future_errc::promise_already_satisfied));
} _Result = _Val;
_Do_notify(_Lock, _At_thread_exit);
} void _Set_value(_Ty&& _Val, bool _At_thread_exit) { // store a result
unique_lock<mutex> _Lock(_Mtx);
_Set_value_raw(_STD forward<_Ty>(_Val), &_Lock, _At_thread_exit);
} void _Set_value_raw(_Ty&& _Val, unique_lock<mutex>* _Lock,
bool _At_thread_exit) { // store a result while inside a locked block
if (_Has_stored_result) {
_Throw_future_error(make_error_code(future_errc::promise_already_satisfied));
} _Result = _STD forward<_Ty>(_Val);
_Do_notify(_Lock, _At_thread_exit);
} void _Set_value(bool _At_thread_exit) { // store a (void) result
unique_lock<mutex> _Lock(_Mtx);
_Set_value_raw(&_Lock, _At_thread_exit);
} void _Set_value_raw(
unique_lock<mutex>* _Lock, bool _At_thread_exit) { // store a (void) result while inside a locked block
if (_Has_stored_result) {
_Throw_future_error(make_error_code(future_errc::promise_already_satisfied));
} _Do_notify(_Lock, _At_thread_exit);
} void _Set_exception(exception_ptr _Exc, bool _At_thread_exit) { // store a result
unique_lock<mutex> _Lock(_Mtx);
_Set_exception_raw(_Exc, &_Lock, _At_thread_exit);
} void _Set_exception_raw(exception_ptr _Exc, unique_lock<mutex>* _Lock,
bool _At_thread_exit) { // store a result while inside a locked block
if (_Has_stored_result) {
_Throw_future_error(make_error_code(future_errc::promise_already_satisfied));
} _Exception = _Exc;
_Do_notify(_Lock, _At_thread_exit);
} bool _Is_ready() const { // return ready status
return _Ready != ;
} bool _Is_ready_at_thread_exit() const { // return ready at thread exit status
return _Ready_at_thread_exit;
} bool _Already_has_stored_result() const { // return presence of stored result
return _Has_stored_result;
} bool _Already_retrieved() const { // return retrieved status
return _Retrieved;
} void _Abandon() { // abandon shared state
unique_lock<mutex> _Lock(_Mtx);
if (!_Has_stored_result) { // queue exception
future_error _Fut(make_error_code(future_errc::broken_promise));
_Set_exception_raw(_STD make_exception_ptr(_Fut), &_Lock, false);
}
} protected:
void _Make_ready_at_thread_exit() { // set ready status at thread exit
if (_Ready_at_thread_exit) {
_Ready = true;
}
} void _Maybe_run_deferred_function(unique_lock<mutex>& _Lock) {
if (!_Running) { //延迟任务默认值为false,只能调用该函数后,才会变为true
_Running = true;
_Run_deferred_function(_Lock); //执行延迟任务
}
} public:
_Ty _Result;
exception_ptr _Exception;
mutex _Mtx;
condition_variable _Cond;
bool _Retrieved; //用于标记_Get_value函数是否己被调用过,true表示己调用过,false为未调用过
int _Ready; //是否处于就绪状态,用于唤醒等待线程。(有些任务做完线程就被置为就绪状态,而有些任务要等线程退出时才置就绪)
bool _Ready_at_thread_exit;//是否在线程退出时才设为就绪状态
bool _Has_stored_result; //调用_Do_notify时表示结果己计算出来,该值被置为true。
bool _Running; //用于标识线程是否正在运行(异步任务默认值为true,延迟任务默认值为false)
private:
virtual bool _Has_deferred_function() const noexcept { // 被_Deferred_async_state子类override
return false;
} virtual void _Run_deferred_function(unique_lock<mutex>&) { // do nothing
} virtual void _Do_notify(unique_lock<mutex>* _Lock, bool _At_thread_exit) { // 通知等待线程。
_Has_stored_result = true;
if (_At_thread_exit) { //线程退出时,才唤醒等待线程
_Cond._Register(*_Lock, &_Ready);
} else { // 立即唤醒等待线程
_Ready = true;
_Cond.notify_all();
}
} void _Delete_this() { // delete this object
if (_Deleter) {
_Deleter->_Delete(this);
} else {
delete this; //删除自身
}
} _Mydel* _Deleter; public:
_Associated_state(const _Associated_state&) = delete; //不可复制
_Associated_state& operator=(const _Associated_state&) = delete; //不可复制赋值
}; // CLASS TEMPLATE _Packaged_state
template <class>
class _Packaged_state; template <class _Ret,
class... _ArgTypes>
class _Packaged_state<_Ret(_ArgTypes...)>
: public _Associated_state<_Ret> { //为packaged_task准备的”共享状态“
public:
using _Mybase = _Associated_state<_Ret>;
using _Mydel = typename _Mybase::_Mydel; template <class _Fty2>
_Packaged_state(const _Fty2& _Fnarg) : _Fn(_Fnarg) { // construct from function object
} #if _HAS_FUNCTION_ALLOCATOR_SUPPORT
template <class _Fty2, class _Alloc>
_Packaged_state(const _Fty2& _Fnarg, const _Alloc& _Al, _Mydel* _Dp)
: _Mybase(_Dp), _Fn(allocator_arg, _Al, _Fnarg) { // construct from function object and allocator
}
#endif // _HAS_FUNCTION_ALLOCATOR_SUPPORT template <class _Fty2>
_Packaged_state(_Fty2&& _Fnarg) : _Fn(_STD forward<_Fty2>(_Fnarg)) { // construct from rvalue function object
} #if _HAS_FUNCTION_ALLOCATOR_SUPPORT
template <class _Fty2, class _Alloc>
_Packaged_state(_Fty2&& _Fnarg, const _Alloc& _Al, _Mydel* _Dp)
: _Mybase(_Dp), _Fn(allocator_arg, _Al,
_STD forward<_Fty2>(_Fnarg)) { // construct from rvalue function object and allocator
}
#endif // _HAS_FUNCTION_ALLOCATOR_SUPPORT //提供给Provider使用的,provider会通过set_value_at_thread_exit调用该函数来实现线程退出时唤醒等待线程。
void _Call_deferred(_ArgTypes... _Args) { //这类延迟函数,在线程退出时将任务设为就绪状态,才会唤醒其他线程。。
_TRY_BEGIN
// call function object and catch exceptions
this->_Set_value(_Fn(_STD forward<_ArgTypes>(_Args)...), true); //执行_Fn函数,并将返回值提供给_Set_value函数。t
_CATCH_ALL //true表示线程退出时才唤醒等待线程
// function object threw exception; record result
this->_Set_exception(_STD current_exception(), true);
_CATCH_END
} //立即调用线程函数,执行完立即唤醒等待线程。比如std::async不管是同步或异步,都是在执行完立即唤醒等待线程。
void _Call_immediate(_ArgTypes... _Args) {
_TRY_BEGIN
// call function object and catch exceptions
this->_Set_value(_Fn(_STD forward<_ArgTypes>(_Args)...), false);//立即调用函数对象,false表示任务做完立即唤醒等待线程
_CATCH_ALL
// function object threw exception; record result
this->_Set_exception(_STD current_exception(), false);
_CATCH_END
} const function<_Ret(_ArgTypes...)>& _Get_fn() { // return stored function object
return _Fn;
} private:
function<_Ret(_ArgTypes...)> _Fn;
}; // CLASS TEMPLATE _Deferred_async_state
template <class _Rx>
class _Deferred_async_state : public _Packaged_state<_Rx()> { //std::async创建的同步”共享状态“
public:
template <class _Fty2>
_Deferred_async_state(const _Fty2& _Fnarg) : _Packaged_state<_Rx()>(_Fnarg) { // construct from function object
} template <class _Fty2>
_Deferred_async_state(_Fty2&& _Fnarg)
: _Packaged_state<_Rx()>(_STD forward<_Fty2>(_Fnarg)) { // construct from rvalue function object
} private:
virtual bool _Has_deferred_function() const
noexcept { // this function is considered to be deferred until it's invoked
return !this->_Running; //如果任务己被执行过,就不在是视为延迟任务
} virtual void _Run_deferred_function(unique_lock<mutex>& _Lock) { // run the deferred function
_Lock.unlock();
_Packaged_state<_Rx()>::_Call_immediate(); //注意,这里不是调用_Call::deferred()!!!
_Lock.lock();
}
}; // CLASS TEMPLATE _Task_async_state
template <class _Rx>
class _Task_async_state : public _Packaged_state<_Rx()> { //std::async创建的异步”共享状态“
public:
using _Mybase = _Packaged_state<_Rx()>;
using _State_type = typename _Mybase::_State_type; template <class _Fty2>
_Task_async_state(_Fty2&& _Fnarg) : _Mybase(_STD forward<_Fty2>(_Fnarg)) { // construct from rvalue function object
_Task = ::Concurrency::create_task([this]() { // do it now
this->_Call_immediate();
}); this->_Running = true; //异步任务,线程一启动就处于running状态。
} virtual ~_Task_async_state() noexcept { // destroy
_Wait(); //异步“共享状态”对象析构时,会被阻塞!!!
} virtual void _Wait() { // wait for completion
_Task.wait(); //重写_Wait()。注意,这里调用的是线程级别的wait,相当于对底层线程实施一次隐式join()。
} virtual _State_type& _Get_value(bool _Get_only_once) { // return the stored result or throw stored exception
_Task.wait(); //异步“共享状态”对象,在调用Get_value时,也会被阻塞!
return _Mybase::_Get_value(_Get_only_once);
} private:
::Concurrency::task<void> _Task;
};
“共享状态”相关类的源码摘要
(二)注意事项
1.std::promise创建_Assoicated_state类型的共享对象。这是一种最简单的共享状态对象,只能用于保存线程函数的返回值等信息。
2. _Package_state类型“共享状态”,除了可以保存返回值外,还用于将可调用对象包装成一个function对象。一般由std::package_task创建。
3._Deffered_async_state或_Task_async_state类型,前者用于跟踪std::launch::deferred类型的异步任务,而后者用于跟踪std::launch::async类型的任务。std::async就是根据启动策略来创建这两种共享状态之一。
4. _Task_async_state类型的“共享状态”对象,在析构时会调用wait()函数来等待任务执行完毕。从效果来看,相当于实施一次隐式join(),正如std::thread一样,C++标准委员会对这种行为也曾经存在争议。而其他所有 “共享状态”的类型都无此操作,这相当于实施一次隐式的detach()操作。
二.期值(“共享状态”的管理器)
(一)future/shared_future源码摘要
// CLASS TEMPLATE _State_manager
template <class _Ty>
class _State_manager { //“共享状态”管理器
public:
_State_manager() : _Assoc_state(nullptr) { // construct with no associated asynchronous state object
_Get_only_once = false; //注意,默认get()函数是可多次调用的
} _State_manager(_Associated_state<_Ty>* _New_state, bool _Get_once)
: _Assoc_state(_New_state) { // construct with _New_state
_Get_only_once = _Get_once;
} _State_manager(const _State_manager& _Other, bool _Get_once = false)
: _Assoc_state(nullptr) { // construct from _Other
_Copy_from(_Other);
_Get_only_once = _Get_once;
} _State_manager(_State_manager&& _Other, bool _Get_once = false)
: _Assoc_state(nullptr) { // construct from rvalue _Other
_Move_from(_Other);
_Get_only_once = _Get_once;
} ~_State_manager() noexcept { // destroy
if (_Assoc_state != nullptr) {
_Assoc_state->_Release(); //_State_manager对象析构时,会同时将管理的“共享状态”的引用计数自减1
}
} _State_manager& operator=(const _State_manager& _Other) { // assign from _Other
_Copy_from(_Other);
return *this;
} _State_manager& operator=(_State_manager&& _Other) { // assign from rvalue _Other
_Move_from(_Other);
return *this;
} //检查当前的 std::future 对象是否有效,即释放与某个共享状态相关联
_NODISCARD bool valid() const noexcept {
return _Assoc_state != nullptr && !(_Get_only_once && _Assoc_state->_Already_retrieved());
} //等待与当前std::future 对象相关联的共享状态的标志变为 ready.
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);
} _Ty& _Get_value() const { // return the stored result or throw stored exception
if (!valid()) {
_Throw_future_error(make_error_code(future_errc::no_state));
} return _Assoc_state->_Get_value(_Get_only_once);
} void _Set_value(const _Ty& _Val, bool _Defer) { // store a result
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) { // store a result
if (!valid()) {
_Throw_future_error(make_error_code(future_errc::no_state));
} _Assoc_state->_Set_value(_STD forward<_Ty>(_Val), _Defer);
} void _Abandon() { // abandon shared state
if (_Assoc_state) {
_Assoc_state->_Abandon();
}
} void _Set_exception(exception_ptr _Exc, bool _Defer) { // store a result
if (!valid()) {
_Throw_future_error(make_error_code(future_errc::no_state));
} _Assoc_state->_Set_exception(_Exc, _Defer);
} void _Swap(_State_manager& _Other) { // exchange with _Other
_STD swap(_Assoc_state, _Other._Assoc_state);
} _Associated_state<_Ty>* _Ptr() const { // return pointer to stored associated asynchronous state object
return _Assoc_state;
} void _Copy_from(const _State_manager& _Other) { // copy stored associated asynchronous state object from _Other
if (this != _STD addressof(_Other)) { // different, copy
if (_Assoc_state) {
_Assoc_state->_Release();
} if (_Other._Assoc_state == nullptr) {
_Assoc_state = nullptr;
} else { // do the copy
_Other._Assoc_state->_Retain();
_Assoc_state = _Other._Assoc_state;
_Get_only_once = _Other._Get_only_once;
}
}
} void _Move_from(_State_manager& _Other) { // move stored associated asynchronous state object from _Other
if (this != _STD addressof(_Other)) { // different, move
if (_Assoc_state) {
_Assoc_state->_Release();
} _Assoc_state = _Other._Assoc_state;
_Other._Assoc_state = nullptr;
_Get_only_once = _Other._Get_only_once;
}
} bool _Is_ready() const { // return ready status
return _Assoc_state && _Assoc_state->_Is_ready();
} bool _Is_ready_at_thread_exit() const { // return ready at thread exit status
return _Assoc_state && _Assoc_state->_Is_ready_at_thread_exit();
} private:
_Associated_state<_Ty>* _Assoc_state;
bool _Get_only_once;
}; // CLASS TEMPLATE future
template <class _Ty>
class shared_future; template <class _Ty>
class future : public _State_manager<_Ty> { // class that defines a non-copyable asynchronous return object
// that holds a value
using _Mybase = _State_manager<_Ty>; public:
future() noexcept { // construct
} future(future&& _Other) noexcept : _Mybase(_STD move(_Other), true) { // true表示get只能被调用一次。
} future& operator=(future&& _Right) noexcept { // assign from rvalue future object
_Mybase::operator=(_STD move(_Right));
return *this;
} future(const _Mybase& _State, _Nil) : _Mybase(_State, true) { // construct from associated asynchronous state object
} ~future() noexcept { // destroy
} _Ty get() { // block until ready then return the stored result or
// throw the stored exception
future _Local{_STD move(*this)}; //注意,移动操作,将使调用get()函数后,future将失去与“共享状态”的关联,valid()变为无效。
return _STD move(_Local._Get_value());
} _NODISCARD shared_future<_Ty> share() noexcept { // return state as shared_future
return shared_future<_Ty>(_STD move(*this));
} future(const future&) = delete;
future& operator=(const future&) = delete;
}; // CLASS TEMPLATE shared_future
template <class _Ty>
class shared_future : public _State_manager<_Ty> { // class that defines a copyable asynchronous return object
// that holds a value
using _Mybase = _State_manager<_Ty>; public:
shared_future() noexcept { // _Mybase中将_Get_Only_once默认值设为false,表示get()可多次调用。
} shared_future(const shared_future& _Other) noexcept : _Mybase(_Other) { //拷贝构造
} shared_future& operator=(const shared_future& _Right) noexcept { // 拷贝赋值 _Mybase::operator=(_Right);
return *this;
} shared_future(future<_Ty>&& _Other) noexcept
: _Mybase(_STD forward<_Mybase>(_Other)) { // 移动构造
} shared_future(shared_future&& _Other) noexcept
: _Mybase(_STD move(_Other)) { // construct from rvalue shared_future object
} shared_future& operator=(shared_future&& _Right) noexcept { // assign from shared_future rvalue object _Mybase::operator=(_STD move(_Right));
return *this;
} ~shared_future() noexcept { // destroy
} const _Ty& get() const { // 阻塞,直到任务就绪。
return this->_Get_value(); //返回值是个只读对象!
}
};
【“共享状态”管理器】相关类的源码摘要
1. std::thread对应着系统的一个底层线程,期值和std::thread对象一样,都可以视为底层线程的句柄,也就是一个线程对象,管理着对应的底层线程。
2. 调用get()时,会阻塞等待直至任务完成。但在future中,get()函数是通过移动语义将异步结果从future中转移给get的返回值,因此该函数只能被调用一次,同时也意味着这个future对象也不可再使用(valid()为false)。而shared_future的get()函数只是简单地返回异步结果的引用,所以可以多次被调用。
3. std::future是只移动类型,而std::shared_future既可移动也可复制。
(1)两者的关系,就如同unique_ptr和shared_ptr。future独占“共享状态”的所有权,而shared_future会共享所有权。当调用future的share()函数时,将创建一个shared_future对象,同时原来的future将失去对“共享状态”对象的所有权,这意味着该future对象不可再使用(其valid()为false)。
(2)shared_future可复制,多线程可共享“共享状态”对象,可用于线程间的通信。此外,在容器中保存期值时,一般使用shared_future类型而不是future类型,首先因为shared_future是可复制的,其次是因为future对象在使用get函数后将变成无效,会导致容器中保存着失效的future。
4. future/shared_future析构时,会将其关联的“共享状态”对象的引用计数自减一次。当引用计数为0时,会同时销毁“共享状态”对象。
5. waitfor()函数返回值的三种状态:
(1)future_status::ready:共享状态的标志已经变为 ready,即 Provider在共享状态上设置了值或者异常。
(2)future_status::timeout:超时,即在规定的时间内共享状态的标志没有变为ready。
(3)future_status::deferred:共享状态包含一个 deferred函数。当使用std::async创建std::launch::deferred任务时,waitfor函数的返回值不是ready,而是deferred!!!
(二)期值的析构行为分析
1. std::thread对象析构时,如果仍处于可联结的状态(未显式调用join()或detach()),那么程序会终止。而future/shared_future对象在析构,有时像是隐式join(),有时像隐式detach(),有时像是二者都没有执行。
2.期值的两种析构行为:
(1)常规行为:析构期值对象本身的成员变量并将其管理的“共享状态”对象的引用计数自减一次。注意,尽管期值的构析行为有时类似于隐式join或detach,但实际上它并不对任何东西实施join或detach。因此,当future配合std::thread使用时,仍需要显式调用std::thread的join或detach以防止程序被终止。这从使用std::thread的角度看也很合理,必须显式调用两者之一。
(2)特殊行为:析构期值时会阻塞线程。根据前面的分析,只有当“共享状态”对象为_Task_async_state类型时,才会阻塞线程直至异步任务结束。
3. 结论:
(1)只有持有_Task_async_state类型的“共享状态”的期值才会阻塞线程。因此,只有同时满足以下三个条件的期值才会表现出特殊行为,任何一个条件不满足时均只表现为常规行为。
①期值所指向的“共享状态”由调用std::async函数创建。
②任务以std::launch::async策略创建。
③该期值是最后一个指向该共享状态的期值。对于std::future而言,由于独占“共享状态”对象的所有权,因此这一点总是成立。对于std::shared_future而言,“共享状态”对象的所有权被shared_future共享,所以只有最后一个指向该对象的shared_future才表现出这种特殊行为。
(2)对于那些由std::async以std::launch::deferred创建的任务,在最后一个期值析构时仍没调用get或wait,则被推迟的任务将不会再有机会运行了。因为最后一个期值将会把“共享状态”对象销毁。
【编程实验】std::future和std::shared_future
#include <iostream>
#include <thread>
#include <future>
#include <chrono>
#include <mutex>
#include <vector> using namespace std; std::mutex g_mtx; int func(int tm, std::promise<int>& pr)
{
auto dura = std::chrono::milliseconds(tm * );
std::this_thread::sleep_for(dura);
pr.set_value(tm); return tm;
} bool check_prime(int x) //判断是否是质数
{
for (int i = ; i < x; ++i){
if (x % i == )
return false;
} return true;
} int calcValue(int x, int y)
{
std::lock_guard<std::mutex> lck(g_mtx);
cout<<"calcValue: x = " << x << ", y = " << y << endl; return x * x + y * y;
} int main()
{
//1.future和shared_future的使用
//shared_future:用于让多个线程同时等待信号
std::promise<void> ready_promise, t1_ready_promise, t2_ready_promise;
std::shared_future<void> ready_future = ready_promise.get_future(); std::chrono::time_point<std::chrono::high_resolution_clock> start; //注意,ready_future按值捕获
auto fun1 = [&, ready_future]()->std::chrono::duration<double, std::milli>
{
t1_ready_promise.set_value();
ready_future.wait(); //等待,接受来自main()的信号
return std::chrono::high_resolution_clock::now() - start; //返回start后多少时间才收到信号
}; auto fun2 = [&, ready_future]()->std::chrono::duration<double, std::milli>
{
t2_ready_promise.set_value();
ready_future.wait(); //等待,接受来自main()的信号
return std::chrono::high_resolution_clock::now() - start; //返回start后多少时间才收到信号
}; auto result1 = std::async(std::launch::async, fun1);
auto result2 = std::async(std::launch::async, fun2); //等待子线程启动完成:确保两个子线程都己经运行,以防止主线程先发通知后子线程才运行。
//两个t1/t2_ready_promise通过set_value通知主线程,两个子线程己全部启动,并进入等待主线程的通知。
t1_ready_promise.get_future().wait();
t2_ready_promise.get_future().wait(); start = std::chrono::high_resolution_clock::now(); //向子线程发送信号
ready_promise.set_value();
std::cout << "Thread 1 received the signal " << result1.get().count() << " ms after start." << endl;
std::cout << "Thread 2 received the signal " << result2.get().count() << " ms after start." << endl; //1.2 用容器保存std::shared_future。
vector<std::shared_future<int>> vec;
auto fut1 = std::async(std::launch::async, [](int a, int b) {return a + b;}, , );
vec.push_back(fut1.share());
std::cout << "The shared_future result is " <<vec[].get() << endl; ////2. wait_for的返回值类型
auto fut2 = std::async(std::launch::deferred, calcValue, , ); //延时函数,同步任务
auto fut3 = std::async(std::launch::async, []() {std::this_thread::sleep_for(1s); });//异步任务 if (fut2.wait_for(0s) == std::future_status::deferred) {
cout <<"fut2 is a deferred task!" << endl;
} cout << "waiting";
while (fut3.wait_for(20ms) != std::future_status::ready) { // std::future_status::timeout
cout << ".";
}
cout << endl; //3. 期值的析构行为
//3.1常规行为:期值析构时,并不对任何东西实施join或detach
{
std::promise<int> pr;
std::future<int> fut = pr.get_future(); std::thread th(func, , std::ref(pr));
th.detach(); //必须确保在th析构前,调用join或detach auto res = fut.get(); cout << res << endl;
} {
std::packaged_task<int(int, int)> pt(calcValue);
auto fut = pt.get_future();
std::thread th(std::move(pt), , ); //pt是只移动类型
cout << fut2.get() << endl;
th.join(); //th析构前,必须调用join()或detach(),可放入get之前或之后。
} //3.2 特殊行为
{
//由async创建的std::launch::async类型的任务,会在fut离开作用域阻塞等待任何完成(类似于隐式join)
auto fut1 = std::async(std::launch::async, calcValue, , ); //std::launch::deferred类型的任务,在fut2离开作用域时并不会阻塞等待(普通析构行为!)。
auto fut2 = std::async(std::launch::deferred, check_prime, ); //如果不调用fut2.get(),任务永远不会被执行。
if (fut2.get()) {//阻塞等待子线程结束,并获取任务的结果。
cout << "123456 is prime." << endl;
}
else {
cout << "123456 is not prime." << endl;
}
} return ;
}
/*输出结果
Thread 1 received the signal 0.0199 ms after start.
Thread 2 received the signal 0.0139 ms after start.
The shared_future result is 5
fut2 is a deferred task!
waiting...............................................
10
calcValue: x = 1, y = 2
5
calcValue: x = 1, y = 2
123456 is not prime.
calcValue: x = 3, y = 4
*/
第27课 “共享状态”及其管理者(std::future/std::shared_future)的更多相关文章
- 第28课 “共享状态”提供者(std::promise/std::package_task)
一. std::promise和std::package_task (一)共享状态.提供者和管理者 // CLASS TEMPLATE _Promise template <class _Ty& ...
- C++11 并发指南四(<future> 详解三 std::future & std::shared_future)
上一讲<C++11 并发指南四(<future> 详解二 std::packaged_task 介绍)>主要介绍了 <future> 头文件中的 std::pack ...
- C++11 并发指南四(<future> 详解三 std::future & std::shared_future)(转)
上一讲<C++11 并发指南四(<future> 详解二 std::packaged_task 介绍)>主要介绍了 <future> 头文件中的 std::pack ...
- C++ 11新特性:std::future & std::shared_future) (转载)
上一讲<C++11 并发指南四(<future> 详解二 std::packaged_task 介绍)>主要介绍了 <future> 头文件中的 std::pack ...
- C++并发编程之std::async(), std::future, std::promise, std::packaged_task
c++11中增加了线程,使得我们可以非常方便的创建线程,它的基本用法是这样的: void f(int n); std::thread t(f, n + 1); t.join(); 但是线程毕竟是属于比 ...
- C++并发高级接口:std::async和std::future
std::async和std::future std::async创建一个后台线程执行传递的任务,这个任务只要是callable object均可,然后返回一个std::future.future储存 ...
- 【C++并发实战】(三) std::future和std::promise
std::future和std::promise std::future std::future期待一个返回,从一个异步调用的角度来说,future更像是执行函数的返回值,C++标准库使用std::f ...
- nodejs学习笔记_nodejs和PHP在基础架构上的差别--共享状态的并发
绝大多数对于Node.js的讨论都把关注点放在了处理高并发能力上,做开发的时候一定要明确node内部做出的权衡,以及node应用性能好的原因. node 为javascript引入了一个复杂的概念,: ...
- 第27课 可变参数模板(8)_TupleHelper
1. TupleHelper的主要功能 (1)打印:由于tuple中的元素是可变参数模板,外部并不知道内部到底是什么数据,有时调试时需要知道其具体值,希望能打印出tuple中所有的元素值. (2)根据 ...
随机推荐
- .NET Core 使用NPOI读取Excel返回泛型List集合
我是一名 ASP.NET 程序员,专注于 B/S 项目开发.累计文章阅读量超过一千万,我的博客主页地址:https://www.itsvse.com/blog_xzz.html 网上有很多关于npoi ...
- ASP.NET Web API 2 的返回结果
HttpResponseMessage IHttpActionResult void 某些其他类型 总结归纳 原文地址:https://www.cnblogs.com/xgzh/p/11208611. ...
- Python 高级特性:切片、迭代、列表生成式、生成器
切片(发现了一些新操作) 参考链接:https://www.liaoxuefeng.com/wiki/1016959663602400/1017269965565856 间隔取元素(可以取负数,负数就 ...
- 基于Spring Cloud Netflix的TCC柔性事务和EDA事件驱动示例
Solar Spring Cloud为开发者提供了快速构建分布式系统中的一些常见工具,如分布式配置中心,服务发现与注册中心,智能路由,服务熔断及降级,消息总线,分布式追踪的解决方案等. 本次实战以模拟 ...
- Linux磁盘系统——磁盘系统简介
Linux磁盘系统——磁盘系统简介 摘要:本文主要学习了Linux系统中有关磁盘的一些知识. 文件系统 说明 硬盘是用来存储数据的,可以将其想象成柜子,只不过柜子是用来存储衣物的.新买来的硬盘,通常要 ...
- java斐波那契数列的顺序输出
斐波那契数列,即1.1.2.3.5......,从第三个数开始包括第三个数,都为这个数的前两个数之和,而第一第二个数都为1. 下面是java输出斐波那契数列的代码: import java.util. ...
- 程序员必备技能之Markdown
Markdown介绍 Markdown是一种纯文本格式的标记语言,比HTML更简单,通过一些简单的语法标记,就可以让文本简洁好看. Markdown已经是程序员一项必备技能了,代码块.流程图.序列图. ...
- elasticsearch: 创建mapping
elasticsearch版本: 6.5.4 创建mapping PUT http://192.168.2.136:9200/index_text/_mapping/text/ { "dyn ...
- Confluence 邮箱设置
Confluence有两种方法设置邮箱 原理: confluence服务器配置好邮箱信息,用户触发邮件发送规则时,confluence服务使用已配置的邮箱信息登录到邮箱服务器,进行发件服务. 那么我们 ...
- Transformer模型---encoder
一.简介 论文链接:<Attention is all you need> 由google团队在2017年发表于NIPS,Transformer 是一种新的.基于 attention 机制 ...