git / moonbite-core / src/libmw/include/mw/common/Lock.h · raw
#pragma once// Copyright (c) 2018-2019 David Burkett// Distributed under the MIT software license, see the accompanying// file LICENSE or http://www.opensource.org/licenses/mit-license.php.#include <memory>#include <shared_mutex>#include <mutex>#include <tuple>template<class T>class Reader{ template<class U> class InnerReader { public: InnerReader(std::shared_ptr<const U> pObject, std::shared_ptr<std::shared_timed_mutex> pMutex, const bool lock, const bool unlock) : m_pObject(pObject), m_pMutex(pMutex), m_unlock(unlock) { if (lock) { m_pMutex->lock_shared(); } } ~InnerReader() { if (m_unlock) { m_pMutex->unlock_shared(); } } std::shared_ptr<const U> m_pObject; std::shared_ptr<std::shared_timed_mutex> m_pMutex; bool m_unlock; };public: static Reader Create(std::shared_ptr<T> pObject, std::shared_ptr<std::shared_timed_mutex> pMutex, const bool lock, const bool unlock) { return Reader(std::shared_ptr<InnerReader<T>>(new InnerReader<T>(pObject, pMutex, lock, unlock))); } Reader() = default; virtual ~Reader() = default; const T* operator->() const { return m_pReader->m_pObject.get(); } const T& operator*() const { return *m_pReader->m_pObject; } std::shared_ptr<const T> GetShared() const { return m_pReader->m_pObject; } bool IsNull() const { return m_pReader->m_pObject == nullptr; }private: Reader(std::shared_ptr<InnerReader<T>> pReader) : m_pReader(pReader) { } std::shared_ptr<InnerReader<T>> m_pReader;};class MutexUnlocker{public: MutexUnlocker(std::shared_ptr<std::shared_timed_mutex> pMutex) : m_pMutex(pMutex) { } ~MutexUnlocker() { m_pMutex->unlock(); }private: std::shared_ptr<std::shared_timed_mutex> m_pMutex;};template<class T>class Writer : virtual public Reader<T>{ template<class U> class InnerWriter { public: InnerWriter(std::shared_ptr<U> pObject, std::shared_ptr<std::shared_timed_mutex> pMutex, const bool lock) : m_pObject(pObject), m_pMutex(pMutex) { if (lock) { m_pMutex->lock(); } } virtual ~InnerWriter() { // Using MutexUnlocker in case exception is thrown. MutexUnlocker unlocker(m_pMutex); } std::shared_ptr<U> m_pObject; std::shared_ptr<std::shared_timed_mutex> m_pMutex; };public: static Writer Create(std::shared_ptr<T> pObject, std::shared_ptr<std::shared_timed_mutex> pMutex, const bool lock) { return Writer(std::shared_ptr<InnerWriter<T>>(new InnerWriter<T>(pObject, pMutex, lock))); } Writer() = default; virtual ~Writer() = default; T* operator->() { return m_pWriter->m_pObject.get(); } const T* operator->() const { return m_pWriter->m_pObject.get(); } T& operator*() { return *m_pWriter->m_pObject; } const T& operator*() const { return *m_pWriter->m_pObject; } std::shared_ptr<T> GetShared() { return m_pWriter->m_pObject; } std::shared_ptr<const T> GetShared() const { return m_pWriter->m_pObject; } bool IsNull() const { return m_pWriter == nullptr; } void Clear() { m_pWriter = nullptr; }private: Writer(std::shared_ptr<InnerWriter<T>> pWriter) : Reader<T>(Reader<T>::Create(pWriter->m_pObject, pWriter->m_pMutex, false, false)), m_pWriter(pWriter) { } std::shared_ptr<InnerWriter<T>> m_pWriter;};template<class T>class Locked{ friend class MultiLocker;public: Locked(std::shared_ptr<T> pObject) : m_pObject(pObject), m_pMutex(std::make_shared<std::shared_timed_mutex>()) { } virtual ~Locked() = default; Reader<T> Read() const { return Reader<T>::Create(m_pObject, m_pMutex, true, true); } Reader<T> Read(std::adopt_lock_t) const { return Reader<T>::Create(m_pObject, m_pMutex, false, true); } Writer<T> Write() { return Writer<T>::Create(m_pObject, m_pMutex, true); } Writer<T> Write(std::adopt_lock_t) { return Writer<T>::Create(m_pObject, m_pMutex, false); }private: std::shared_ptr<T> m_pObject; std::shared_ptr<std::shared_timed_mutex> m_pMutex;};