#pragma once #include #include #include namespace DB { /** SharedMutexHelper class allows to inject specific logic when underlying shared mutex is acquired * and released. * * Example: * * class ProfileSharedMutex : public SharedMutexHelper * { * public: * size_t getLockCount() const { return lock_count; } * * size_t getSharedLockCount() const { return shared_lock_count; } * * private: * using Base = SharedMutexHelper; * friend class SharedMutexHelper; * * void lockImpl() * { * ++lock_count; * Base::lockImpl(); * } * * void lockSharedImpl() * { * ++shared_lock_count; * Base::lockSharedImpl(); * } * * std::atomic lock_count = 0; * std::atomic shared_lock_count = 0; * }; */ template class TSA_CAPABILITY("SharedMutexHelper") SharedMutexHelper { public: // Exclusive ownership void lock() TSA_ACQUIRE() /// NOLINT { static_cast(this)->lockImpl(); } bool try_lock() TSA_TRY_ACQUIRE(true) /// NOLINT { static_cast(this)->tryLockImpl(); } void unlock() TSA_RELEASE() /// NOLINT { static_cast(this)->unlockImpl(); } // Shared ownership void lock_shared() TSA_ACQUIRE_SHARED() /// NOLINT { static_cast(this)->lockSharedImpl(); } bool try_lock_shared() TSA_TRY_ACQUIRE_SHARED(true) /// NOLINT { static_cast(this)->tryLockSharedImpl(); } void unlock_shared() TSA_RELEASE_SHARED() /// NOLINT { static_cast(this)->unlockSharedImpl(); } protected: void lockImpl() TSA_NO_THREAD_SAFETY_ANALYSIS { mutex.lock(); } void tryLockImpl() TSA_NO_THREAD_SAFETY_ANALYSIS { mutex.try_lock(); } void unlockImpl() TSA_NO_THREAD_SAFETY_ANALYSIS { mutex.unlock(); } void lockSharedImpl() TSA_NO_THREAD_SAFETY_ANALYSIS { mutex.lock_shared(); } void tryLockSharedImpl() TSA_NO_THREAD_SAFETY_ANALYSIS { mutex.try_lock_shared(); } void unlockSharedImpl() TSA_NO_THREAD_SAFETY_ANALYSIS { mutex.unlock_shared(); } MutexType mutex; }; }