From bbc746d34a9926805350579c8e2d07ae25de3d5a Mon Sep 17 00:00:00 2001 From: greg Date: Sat, 13 Apr 2019 20:22:13 -0400 Subject: [PATCH] add support for absl::Mutex --- benchmark/bench.cc | 7 +- examples/bench.cc | 6 +- parallel_hashmap/phmap_base.h | 215 +++++++++++++++++++++++++--------- 3 files changed, 164 insertions(+), 64 deletions(-) diff --git a/benchmark/bench.cc b/benchmark/bench.cc index 5619d67..7e6eb24 100644 --- a/benchmark/bench.cc +++ b/benchmark/bench.cc @@ -28,12 +28,7 @@ #if 1 // use Abseil's mutex... faster #include "absl/synchronization/mutex.h" - struct AbslMutex : protected absl::Mutex - { - void lock() { this->Lock(); } - void unlock() { this->Unlock(); } - }; - #define MTX AbslMutex //std::mutex + #define MTX absl::Mutex #else #include #define MTX std::mutex diff --git a/examples/bench.cc b/examples/bench.cc index 8f208b2..0d857c2 100644 --- a/examples/bench.cc +++ b/examples/bench.cc @@ -13,6 +13,10 @@ #if 1 #include #define MTX std::mutex + #elif 0 + // Abseil's mutexes are very efficient (at least on windows) + #include "absl/synchronization/mutex.h" + #define MTX absl::Mutex #elif 0 #include #include @@ -415,7 +419,7 @@ int main(int argc, char ** argv) #endif else if(!strcmp(argv[2], "random")) { - fprintf(stderr, "size = %llu\n", sizeof(hash)); + fprintf(stderr, "size = %zu\n", sizeof(hash)); timer = _fill_random2(num_keys, hash); //out("random", num_keys, timer); //fprintf(stderr, "inserted %llu\n", hash.size()); diff --git a/parallel_hashmap/phmap_base.h b/parallel_hashmap/phmap_base.h index 490fdb9..0cff3d5 100644 --- a/parallel_hashmap/phmap_base.h +++ b/parallel_hashmap/phmap_base.h @@ -4587,74 +4587,63 @@ public: bool owns_lock() const noexcept { return true; } }; - class ScopedLock + class WriteLock { public: typedef Mutex mutex_type; - ScopedLock() : - m_(nullptr), locked_(false) - {} + WriteLock() : m_(nullptr), locked_(false) {} - explicit ScopedLock(Mutex &m) : - m_(&m) - { + explicit WriteLock(Mutex &m) : m_(&m) { m_->lock(); locked_ = true; } - ScopedLock(Mutex& m, adopt_lock_t) noexcept : + WriteLock(Mutex& m, adopt_lock_t) noexcept : m_(&m), locked_(true) {} - ScopedLock(Mutex& m, defer_lock_t) noexcept : + WriteLock(Mutex& m, defer_lock_t) noexcept : m_(&m), locked_(false) {} - ScopedLock(Mutex& m, try_to_lock_t) : - m_(&m), locked_(false) - { + WriteLock(Mutex& m, try_to_lock_t) : + m_(&m), locked_(false) { try_lock(); } - ScopedLock(ScopedLock &&o) : - m_(std::move(o.m_)), locked_(std::move(o.locked_)) - { + WriteLock(WriteLock &&o) : + m_(std::move(o.m_)), locked_(std::move(o.locked_)) { o.locked_ = false; o.m_ = nullptr; } - ScopedLock& operator=(ScopedLock&& other) - { - ScopedLock temp(std::move(other)); + WriteLock& operator=(WriteLock&& other) { + WriteLock temp(std::move(other)); swap(temp); return *this; } - ~ScopedLock() - { + ~WriteLock() { if (locked_) m_->unlock(); } - void lock() - { + void lock() { if (!locked_) { m_->lock(); locked_ = true; } } - void unlock() - { + void unlock() { if (locked_) { m_->unlock(); locked_ = false; } } - bool try_lock() - { + bool try_lock() { if (locked_) return true; locked_ = m_->try_lock(); @@ -4663,8 +4652,84 @@ public: bool owns_lock() const noexcept { return locked_; } - void swap(ScopedLock &o) noexcept - { + void swap(WriteLock &o) noexcept { + std::swap(m_, o.m_); + std::swap(locked_, o.locked_); + } + + Mutex *mutex() const noexcept { return m_; } + + private: + Mutex *m_; + bool locked_; + }; + + class ReadLock + { + public: + typedef Mutex mutex_type; + + ReadLock() : m_(nullptr), locked_(false) {} + + explicit ReadLock(Mutex &m) : m_(&m) { + m_->lock_shared(); + locked_ = true; + } + + ReadLock(Mutex& m, adopt_lock_t) noexcept : + m_(&m), locked_(true) + {} + + ReadLock(Mutex& m, defer_lock_t) noexcept : + m_(&m), locked_(false) + {} + + ReadLock(Mutex& m, try_to_lock_t) : + m_(&m), locked_(false) { + try_lock_shared(); + } + + ReadLock(ReadLock &&o) : + m_(std::move(o.m_)), locked_(std::move(o.locked_)) { + o.locked_ = false; + o.m_ = nullptr; + } + + ReadLock& operator=(ReadLock&& other) { + ReadLock temp(std::move(other)); + swap(temp); + return *this; + } + + ~ReadLock() { + if (locked_) + m_->unlock_shared(); + } + + void lock() { + if (!locked_) { + m_->lock_shared(); + locked_ = true; + } + } + + void unlock() { + if (locked_) { + m_->unlock_shared(); + locked_ = false; + } + } + + bool try_lock() { + if (locked_) + return true; + locked_ = m_->try_lock_shared(); + return locked_; + } + + bool owns_lock() const noexcept { return locked_; } + + void swap(ReadLock &o) noexcept { std::swap(m_, o.m_); std::swap(locked_, o.locked_); } @@ -4692,21 +4757,25 @@ public: // } // // --------------------------------------------------------------------------- +// Generic mutex support (always write locks) +// -------------------------------------------------------------------------- template -class LockableImpl : public Mtx_, public LockableBaseImpl +class LockableImpl : public Mtx_ { public: using mutex_type = Mtx_; using Base = LockableBaseImpl; - using SharedLock = typename Base::ScopedLock; - using UpgradeLock = typename Base::ScopedLock; - using UniqueLock = typename Base::ScopedLock; + using SharedLock = typename Base::WriteLock; + using UpgradeLock = typename Base::WriteLock; + using UniqueLock = typename Base::WriteLock; using UpgradeToUnique = typename Base::DoNothing; // we already have unique ownership }; +// --------------------------------------------------------------------------- +// Null mutex (no-op) - when we don't want internal synchronization // --------------------------------------------------------------------------- template <> -class LockableImpl: public phmap::NullMutex, public LockableBaseImpl +class LockableImpl: public phmap::NullMutex { public: using mutex_type = phmap::NullMutex; @@ -4717,36 +4786,68 @@ public: using UpgradeToUnique = typename Base::DoNothing; }; +// -------------------------------------------------------------------------- +// Abseil Mutex support (read and write lock support) +// -------------------------------------------------------------------------- +#ifdef ABSL_SYNCHRONIZATION_MUTEX_H_ + + struct AbslMutex : protected absl::Mutex + { + void lock() { this->Lock(); } + void unlock() { this->Unlock(); } + void try_lock() { this->TryLock(); } + void lock_shared() { this->ReaderLock(); } + void unlock_shared() { this->ReaderUnlock(); } + void try_lock_shared() { this->ReaderTryLock(); } + }; + + template <> + class LockableImpl : public AbslMutex + { + public: + using mutex_type = phmap::AbslMutex; + using Base = LockableBaseImpl; + using SharedLock = typename Base::ReadLock; + using UpgradeLock = typename Base::WriteLock; + using UniqueLock = typename Base::WriteLock; + using UpgradeToUnique = typename Base::DoNothing; // we already have unique ownership + }; + +#endif + +// -------------------------------------------------------------------------- +// Boost shared_mutex support (read and write lock support) +// -------------------------------------------------------------------------- #ifdef PHMAP_HAS_BOOST_THREAD_MUTEXES #if 1 -// --------------------------------------------------------------------------- -template <> -class LockableImpl : public boost::shared_mutex -{ -public: - using mutex_type = boost::shared_mutex; - using Base = LockableBaseImpl; - using SharedLock = boost::shared_lock; - using UpgradeLock = boost::unique_lock; // we assume that boost::shared_mutex can't upgrade - using UniqueLock = boost::unique_lock; - using UpgradeToUnique = typename Base::DoNothing; // we already have unique ownership -}; + // --------------------------------------------------------------------------- + template <> + class LockableImpl : public boost::shared_mutex + { + public: + using mutex_type = boost::shared_mutex; + using Base = LockableBaseImpl; + using SharedLock = boost::shared_lock; + using UpgradeLock = boost::unique_lock; // assume can't upgrade + using UniqueLock = boost::unique_lock; + using UpgradeToUnique = typename Base::DoNothing; // we already have unique ownership + }; #else -// --------------------------------------------------------------------------- -template <> -class LockableImpl : public boost::upgrade_mutex -{ -public: - using mutex_type = boost::upgrade_mutex; - using SharedLock = boost::shared_lock; - using UpgradeLock = boost::upgrade_lock; - using UniqueLock = boost::unique_lock; - using UpgradeToUnique = boost::upgrade_to_unique_lock; -}; + // --------------------------------------------------------------------------- + template <> + class LockableImpl : public boost::upgrade_mutex + { + public: + using mutex_type = boost::upgrade_mutex; + using SharedLock = boost::shared_lock; + using UpgradeLock = boost::upgrade_lock; + using UniqueLock = boost::unique_lock; + using UpgradeToUnique = boost::upgrade_to_unique_lock; + }; #endif -#endif +#endif // PHMAP_HAS_BOOST_THREAD_MUTEXES } // phmap