#ifndef UDPC_CXX11_SHARED_SPIN_LOCK_H_ #define UDPC_CXX11_SHARED_SPIN_LOCK_H_ #include #include namespace UDPC { // Forward declaration for LockObj. class SharedSpinLock; class Badge { public: static Badge newInvalid(); // Disallow copy. Badge(const Badge&) = delete; Badge& operator=(const Badge&) = delete; // Allow move. Badge(Badge&&) = default; Badge& operator=(Badge&&) = default; private: friend class SharedSpinLock; // Can only be created by SharedSpinLock. Badge(); bool isValid; }; template class LockObj { public: // Invalid instance constructor. LockObj(); ~LockObj(); // Explicit invalid instance constructor. static LockObj newInvalid(); // Disallow copy. LockObj(const LockObj&) = delete; LockObj& operator=(const LockObj&) = delete; // Allow move. LockObj(LockObj&&) = default; LockObj& operator=(LockObj&&) = default; bool isValid() const; private: friend class SharedSpinLock; // Only can be created by SharedSpinLock. LockObj(Badge &&badge); LockObj(std::weak_ptr lockPtr, Badge &&badge); std::weak_ptr weakPtrLock; bool isLocked; Badge badge; }; class SharedSpinLock { public: using Ptr = std::shared_ptr; using Weak = std::weak_ptr; static Ptr newInstance(); // Disallow copy. SharedSpinLock(const SharedSpinLock&) = delete; SharedSpinLock& operator=(const SharedSpinLock&) = delete; // Enable move. SharedSpinLock(SharedSpinLock&&) = default; SharedSpinLock& operator=(SharedSpinLock&&) = default; LockObj spin_read_lock(); LockObj try_spin_read_lock(); void read_unlock(Badge&&); LockObj spin_write_lock(); LockObj try_spin_write_lock(); void write_unlock(Badge&&); LockObj trade_write_for_read_lock(LockObj&); LockObj try_trade_write_for_read_lock(LockObj&); LockObj trade_read_for_write_lock(LockObj&); LockObj try_trade_read_for_write_lock(LockObj&); private: SharedSpinLock(); Weak selfWeakPtr; /// Used to lock the read/write member variables. std::atomic_bool spinLock; unsigned int read; bool write; }; template LockObj::LockObj() : weakPtrLock(), isLocked(false), badge(UDPC::Badge::newInvalid()) {} template LockObj::LockObj(Badge &&badge) : weakPtrLock(), isLocked(false), badge(std::forward(badge)) {} template LockObj::LockObj(SharedSpinLock::Weak lockPtr, Badge &&badge) : weakPtrLock(lockPtr), isLocked(true), badge(std::forward(badge)) {} template LockObj::~LockObj() { if (!isLocked) { return; } auto strongPtrLock = weakPtrLock.lock(); if (strongPtrLock) { if (IsWriteObj) { strongPtrLock->write_unlock(std::move(badge)); } else { strongPtrLock->read_unlock(std::move(badge)); } } } template LockObj LockObj::newInvalid() { return LockObj{}; } template bool LockObj::isValid() const { return isLocked; } } // namespace UDPC #endif