GCC STL源码解析(七) —— future & promise

本文详细解析了GCC STL中的future和promise,包括它们的主要代码结构、状态管理、线程同步机制以及不同类型的特化形式。通过分析future和promise的内部实现,深入理解异步编程在C++中的应用。
摘要由CSDN通过智能技术生成

future & promise

1 主要代码

1.1 future

future_status
enum class future_status {
    ready, timeout, deferred };

共三个状态:就绪、超时、延迟。

__future_base

/// Base class and enclosing scope.
struct __future_base {
   
    /// Base class for results.
    struct _Result_base {
   
        exception_ptr _M_error;

        _Result_base(const _Result_base&) = delete;
        _Result_base& operator=(const _Result_base&) = delete;

        // _M_destroy() allows derived classes to control deallocation
        virtual void _M_destroy() = 0;

        struct _Deleter {
   
            void operator()(_Result_base* __fr) const {
    __fr->_M_destroy(); }
        };

    protected:
        _Result_base();
        virtual ~_Result_base();
    };

    /// A unique_ptr for result objects.
    template <typename _Res>
    using _Ptr = unique_ptr<_Res, _Result_base::_Deleter>;

    /// A result object that has storage for an object of type _Res.
    template <typename _Res>
    struct _Result : _Result_base {
   
    private:
        __gnu_cxx::__aligned_buffer<_Res> _M_storage;
        bool _M_initialized;

    public:
        typedef _Res result_type;

        _Result() noexcept : _M_initialized() {
   }

        ~_Result() {
   
            if (_M_initialized) _M_value().~_Res();
        }

        // Return lvalue, future will add const or rvalue-reference
        _Res& _M_value() noexcept {
    return *_M_storage._M_ptr(); }

        void _M_set(const _Res& __res) {
   
            ::new (_M_storage._M_addr()) _Res(__res);
            _M_initialized = true;
        }

        void _M_set(_Res&& __res) {
   
            ::new (_M_storage._M_addr()) _Res(std::move(__res));
            _M_initialized = true;
        }

    private:
        void _M_destroy() {
    delete this; }
    };

    /// A result object that uses an allocator.
    template <typename _Res, typename _Alloc>
    struct _Result_alloc final : _Result<_Res>, _Alloc {
   
        using __allocator_type = __alloc_rebind<_Alloc, _Result_alloc>;

        explicit _Result_alloc(const _Alloc& __a) : _Result<_Res>(), _Alloc(__a) {
   }

    private:
        void _M_destroy() {
   
            __allocator_type __a(*this);
            __allocated_ptr<__allocator_type> __guard_ptr{
   __a, this};
            this->~_Result_alloc();
        }
    };

    // Create a result object that uses an allocator.
    template <typename _Res, typename _Allocator>
    static _Ptr<_Result_alloc<_Res, _Allocator> > _S_allocate_result(const _Allocator& __a) {
   
        using __result_type = _Result_alloc<_Res, _Allocator>;
        typename __result_type::__allocator_type __a2(__a);
        auto __guard = std::__allocate_guarded(__a2);
        __result_type* __p = ::new ((void*)__guard.get()) __result_type{
   __a};
        __guard = nullptr;
        return _Ptr<__result_type>(__p);
    }

    // Keep it simple for std::allocator.
    template <typename _Res, typename _Tp>
    static _Ptr<_Result<_Res> > _S_allocate_result(const std::allocator<_Tp>& __a) {
   
        return _Ptr<_Result<_Res> >(new _Result<_Res>);
    }

    // Base class for various types of shared state created by an
    // asynchronous provider (such as a std::promise) and shared with one
    // or more associated futures.
    class _State_baseV2 {
   
        typedef _Ptr<_Result_base> _Ptr_type;

        enum _Status : unsigned {
    __not_ready, __ready };

        _Ptr_type _M_result;
        __atomic_futex_unsigned<> _M_status;
        atomic_flag _M_retrieved = ATOMIC_FLAG_INIT;
        once_flag _M_once;

    public:
        _State_baseV2() noexcept : _M_result(), _M_status(_Status::__not_ready) {
   }
        _State_baseV2(const _State_baseV2&) = delete;
        _State_baseV2& operator=(const _State_baseV2&) = delete;
        virtual ~_State_baseV2() = default;

        _Result_base& wait() {
   
            // Run any deferred function or join any asynchronous thread:
            _M_complete_async();
            // Acquire MO makes sure this synchronizes with the thread that made
            // the future ready.
            _M_status._M_load_when_equal(_Status::__ready, memory_order_acquire);
            return *_M_result;
        }

        template <typename _Rep, typename _Period>
        future_status wait_for(const chrono::duration<_Rep, _Period>& __rel) {
   
            // First, check if the future has been made ready.  Use acquire MO
            // to synchronize with the thread that made it ready.
            if (_M_status._M_load(memory_order_acquire) == _Status::__ready) return future_status::ready;

            if (_M_is_deferred_future()) return future_status::deferred;

            // Don't wait unless the relative time is greater than zero.
            if (__rel > __rel.zero() &&
                _M_status._M_load_when_equal_for(_Status::__ready, memory_order_acquire, __rel)) {
   
                // _GLIBCXX_RESOLVE_LIB_DEFECTS
                // 2100.  timed waiting functions must also join
                // This call is a no-op by default except on an async future,
                // in which case the async thread is joined.  It's also not a
                // no-op for a deferred future, but such a future will never
                // reach this point because it returns future_status::deferred
                // instead of waiting for the future to become ready (see
                // above).  Async futures synchronize in this call, so we need
                // no further synchronization here.
                _M_complete_async();

                return future_status::ready;
            }
            return future_status::timeout;
        }

        template <typename _Clock, typename _Duration>
        future_status wait_until(const chrono::time_point<_Clock, _Duration>& __abs) {
   
#if __cplusplus > 201703L
            static_assert(chrono::is_clock_v<_Clock>);
#endif
            // First, check if the future has been made ready.  Use acquire MO
            // to synchronize with the thread that made it ready.
            if (_M_status._M_load(memory_order_acquire) == _Status::__ready) return future_status::ready;

            if (_M_is_deferred_future()) return future_status::deferred;

            if (_M_status._M_load_when_equal_until(_Status::__ready, memory_order_acquire, __abs)) {
   
                // _GLIBCXX_RESOLVE_LIB_DEFECTS
                // 2100.  timed waiting functions must also join
                // See wait_for(...) above.
                _M_complete_async();

                return future_status::ready;
            }
            return future_status::timeout;
        }

        // Provide a result to the shared state and make it ready.
        // Calls at most once: _M_result = __res();
        void _M_set_result(function<_Ptr_type()> __res, bool __ignore_failure = false) {
   
            bool __did_set = false;
            // all calls to this function are serialized,
            // side-effects of invoking __res only happen once
            call_once(_M_once, &_State_baseV2::_M_do_set, this, std::__addressof(__res),
                      std::__addressof(__did_set));
            if (__did_set)
                // Use release MO to synchronize with observers of the ready state.
                _M_status._M_store_notify_all(_Status::__ready, memory_order_release);
            else if (!__ignore_failure)
                __throw_future_error(int(future_errc::promise_already_satisfied));
        }

        // Provide a result to the shared state but delay making it ready
        // until the calling thread exits.
        // Calls at most once: _M_result = __res();
        void _M_set_delayed_result(function<_Ptr_type()> __res, weak_ptr<_State_baseV2> __self) {
   
            bool __did_set = false;
            unique_ptr<_Make_ready> __mr{
   new _Make_ready};
            // all calls to this function are serialized,
            // side-effects of invoking __res only happen once
            call_once(_M_once, &_State_baseV2::_M_do_set, this, std::__addressof(__res),
                      std::__addressof(__did_set));
            if (!__did_set) __throw_future_error(int(future_errc::promise_already_satisfied));
            __mr->_M_shared_state = std::move(__self);
            __mr->_M_set();
            __mr.release();
        }

        // Abandon this shared state.
        void _M_break_promise(_Ptr_type __res) {
   
            if (static_cast<bool>(__res)) {
   
                __res->_M_error = make_exception_ptr(future_error(future_errc::broken_promise));
                // This function is only called when the last asynchronous result
                // provider is abandoning this shared state, so noone can be
                // trying to make the shared state ready at the same time, and
                // we can access _M_result directly instead of through call_once.
                _M_result.swap(__res);
                // Use release MO to synchronize with observers of the ready state.
                _M_status._M_store_notify_all(_Status::__ready, memory_order_release);
            }
        }

        // Called when this object is first passed to a future.
        void _M_set_retrieved_flag() {
   
            if (_M_retrieved.test_and_set()) __throw_future_error(int(future_errc::future_already_retrieved));
        }

        template <typename _Res, typename _Arg>
        struct _Setter;

        // set lvalues
        template <typename _Res, typename _Arg>
        struct _Setter<_Res, _Arg&> {
   
            // check this is only used by promise<R>::set_value(const R&)
            // or promise<R&>::set_value(R&)
            static_assert(is_same<_Res, _Arg&>::value               // promise<R&>
                              || is_same<const _Res, _Arg>::value,  // promise<R>
                          "Invalid specialisation");

            // Used by std::promise to copy construct the result.
            typename promise<_Res>::_Ptr_type operator()() const {
   
                _M_promise->_M_storage->_M_set(*_M_arg);
                return std::move(_M_promise->_M_storage);
            }
            promise<_Res>* _M_promise;
            _Arg* _M_arg;
        };

        // set rvalues
        template <typename _Res>
        struct _Setter<_Res, _Res&&> {
   
            // Used by std::promise to move construct the result.
            typename promise<_Res>::_Ptr_type operator()() const {
   
                _M_promise->_M_storage->_M_set(std::move(*_M_arg));
                return std::move(_M_promise->_M_storage);
            }
            promise<_Res>* _M_promise;
            _Res* _M_arg;
        };

        // set void
        template <typename _Res>
        struct _Setter<_Res, void> {
   
            static_assert(is_void<_Res>::value, "Only used for promise<void>");

            typename promise<_Res>::_Ptr_type operator()() const {
    return std::move(_M_promise->_M_storage); }

            promise<_Res>* _M_promise;
        };

        struct __exception_ptr_tag {
   };

        // set exceptions
        template <typename _Res>
        struct _Setter<_Res, __exception_ptr_tag> {
   
            // Used by std::promise to store an exception as the result.
            typename promise<_Res>::_Ptr_type operator()() const {
   
                _M_promise->_M_storage->_M_error = *_M_ex;
                return std::move(_M_promise->_M_storage);
            }

            promise<_Res>* _M_promise;
            exception_ptr* _M_ex;
        };

        template <typename _Res, typename _Arg>
        static _Setter<_Res, _Arg&&> __setter(promise<_Res>* __prom, _Arg&& __arg) {
   
            _S_check(__prom->_M_future);
            return _Setter<_Res, _Arg&&>{
   __prom, std::__addressof(__arg)};
        }

        template <typename _Res>
        static _Setter<_Res, __exception_ptr_tag> __setter(exception_ptr& __ex, promise<_Res>* __prom) {
   
            _S_check(__prom->_M_future);
            return _Setter<_Res, __exception_ptr_tag>{
   __prom, &__ex};
        }

        template <typename _Res>
        static _Setter<_Res, void> __setter(promise<_Res>* __prom) {
   
            _S_check(__prom->_M_future);
            return _Setter<_Res, void>{
   __prom};
        }

        template <typename _Tp>
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值