diff options
-rw-r--r-- | src/node_mutex.h | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/src/node_mutex.h b/src/node_mutex.h index 807e1444f1..b82505cc63 100644 --- a/src/node_mutex.h +++ b/src/node_mutex.h @@ -6,6 +6,9 @@ #include "util.h" #include "uv.h" +#include <memory> // std::shared_ptr<T> +#include <utility> // std::forward<T> + namespace node { template <typename Traits> class ConditionVariableBase; @@ -15,6 +18,51 @@ struct LibuvMutexTraits; using ConditionVariable = ConditionVariableBase<LibuvMutexTraits>; using Mutex = MutexBase<LibuvMutexTraits>; +template <typename T, typename MutexT = Mutex> +class ExclusiveAccess { + public: + ExclusiveAccess() = default; + + template <typename... Args> + explicit ExclusiveAccess(Args&&... args) + : item_(std::forward<Args>(args)...) {} + + ExclusiveAccess(const ExclusiveAccess&) = delete; + ExclusiveAccess& operator=(const ExclusiveAccess&) = delete; + + class Scoped { + public: + // ExclusiveAccess will commonly be used in conjuction with std::shared_ptr + // and without this constructor it's too easy to forget to keep a reference + // around to the shared_ptr while operating on the ExclusiveAccess object. + explicit Scoped(const std::shared_ptr<ExclusiveAccess>& shared) + : shared_(shared) + , scoped_lock_(shared->mutex_) + , pointer_(&shared->item_) {} + + explicit Scoped(ExclusiveAccess* exclusive_access) + : shared_() + , scoped_lock_(exclusive_access->mutex_) + , pointer_(&exclusive_access->item_) {} + + T& operator*() const { return *pointer_; } + T* operator->() const { return pointer_; } + + Scoped(const Scoped&) = delete; + Scoped& operator=(const Scoped&) = delete; + + private: + std::shared_ptr<ExclusiveAccess> shared_; + typename MutexT::ScopedLock scoped_lock_; + T* const pointer_; + }; + + private: + friend class ScopedLock; + MutexT mutex_; + T item_; +}; + template <typename Traits> class MutexBase { public: |