diff --git a/parallel_hashmap/phmap.h b/parallel_hashmap/phmap.h index 5281eb4..299a16e 100644 --- a/parallel_hashmap/phmap.h +++ b/parallel_hashmap/phmap.h @@ -4333,23 +4333,6 @@ struct HashtableDebugAccess> } // namespace hashtable_debug_internal } // namespace container_internal -// ----------------------------------------------------------------------------- -// NullMutex -// ----------------------------------------------------------------------------- -// A class that implements the Mutex interface, but does nothing. This is to be -// used as a default template parameters for classes who provide optional -// internal locking (like phmap::parallel_flat_hash_map). -// ----------------------------------------------------------------------------- -class PHMAP_LOCKABLE NullMutex { -public: - NullMutex() {} - ~NullMutex() {} - void lock() PHMAP_EXCLUSIVE_LOCK_FUNCTION() {} - void unlock() PHMAP_UNLOCK_FUNCTION() {} - bool try_lock() PHMAP_EXCLUSIVE_TRYLOCK_FUNCTION(true) { return true; } -}; - - // ----------------------------------------------------------------------------- // phmap::flat_hash_set // ----------------------------------------------------------------------------- diff --git a/parallel_hashmap/phmap_base.h b/parallel_hashmap/phmap_base.h index d08951c..9b438ef 100644 --- a/parallel_hashmap/phmap_base.h +++ b/parallel_hashmap/phmap_base.h @@ -4506,6 +4506,22 @@ inline T& ts_unchecked_read(T& v) PHMAP_NO_THREAD_SAFETY_ANALYSIS { namespace phmap { +// ----------------------------------------------------------------------------- +// NullMutex +// ----------------------------------------------------------------------------- +// A class that implements the Mutex interface, but does nothing. This is to be +// used as a default template parameters for classes who provide optional +// internal locking (like phmap::parallel_flat_hash_map). +// ----------------------------------------------------------------------------- +class NullMutex { +public: + NullMutex() {} + ~NullMutex() {} + void lock() {} + void unlock() {} + bool try_lock() { return true; } +}; + struct adopt_lock_t { explicit adopt_lock_t() = default; }; struct defer_lock_t { explicit defer_lock_t() = default; }; struct try_to_lock_t { explicit try_to_lock_t() = default; }; @@ -4543,16 +4559,16 @@ private: // ------------------------ lockable object used internally ------------------------- template -class LockableBase +class LockableBaseImpl { public: struct DoNothing { DoNothing() {} explicit DoNothing(Mutex& ) noexcept {} - DoNothing(Mutex&, adopt_lock_t) noexcept {} - DoNothing(Mutex&, defer_lock_t) noexcept {} - DoNothing(Mutex&, try_to_lock_t) {} + DoNothing(Mutex&, phmap::adopt_lock_t) noexcept {} + DoNothing(Mutex&, phmap::defer_lock_t) noexcept {} + DoNothing(Mutex&, phmap::try_to_lock_t) {} void lock() {} void unlock() {} bool try_lock() { return true; } @@ -4617,28 +4633,69 @@ public: }; }; -// ------------------------ holds a mutex +// ------------------------ holds a mutex ------------------------------------ // Default implementation for Lockable, should work fine for std::mutex +// ----------------------------------- +// use as: +// using Lockable = phmap::LockableImpl; +// Lockable m; +// +// Lockable::UpgradeLock read_lock(m); // take a upgradable lock +// +// { +// Lockable::UpgradeToUnique unique_lock(read_lock); +// // now locked for write +// } +// // --------------------------------------------------------------------------- template -class Lockable : public Mutex, public LockableBase +class LockableImpl : public Mutex, public LockableBaseImpl { public: - using Base = LockableBase; + using mutex_type = Mutex; + using Base = LockableBaseImpl; using SharedLock = typename Base::ScopedLock; + using UpgradeLock = typename Base::ScopedLock; using UniqueLock = typename Base::ScopedLock; using UpgradeToUnique = typename Base::DoNothing; // we already have unique ownership }; +// --------------------------------------------------------------------------- +template <> +class LockableImpl: public LockableBaseImpl +{ +public: + using mutex_type = phmap::NullMutex; + using Base = LockableBaseImpl; + using SharedLock = typename Base::DoNothing; + using UpgradeLock = typename Base::DoNothing; + using UniqueLock = typename Base::DoNothing; + using UpgradeToUnique = typename Base::DoNothing; +}; + #if defined(BOOST_THREAD_SHARED_MUTEX_HPP) && defined(BOOST_THREAD_LOCK_TYPES_HPP) +// --------------------------------------------------------------------------- template <> -class Lockable : public boost::shared_mutex +class LockableImpl : public boost::shared_mutex { public: using mutex_type = boost::shared_mutex; + using SharedLock = boost::shared_lock; + using UpgradeLock = boost::unique_lock; // we assume that shared can't upgrade using UniqueLock = boost::unique_lock; - using SharedLock = boost::upgrade_lock; + using UpgradeToUnique = typename Base::DoNothing; // we already have unique ownership +}; + +// --------------------------------------------------------------------------- +template <> +class LockableImpl : public boost::upgrade_mutex +{ +public: + using mutex_type = boost::upgrade_mutex; + using UniqueLock = boost::unique_lock; + using SharedLock = boost::shared_lock; + using UpgradeLock = boost::upgrade_lock; using UpgradeToUnique = boost::upgrade_to_unique_lock; };