From: Remi Gacogne Date: Fri, 16 Apr 2021 13:34:50 +0000 (+0200) Subject: Introduce LockGuarded, a lock-protected data X-Git-Tag: dnsdist-1.7.0-alpha1~62^2~31 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=92d5b988194b55772a146ba90c9b0d73d970a843;p=thirdparty%2Fpdns.git Introduce LockGuarded, a lock-protected data The general idea has been borrowed from Rust's locks: instead of defining two objects, the one to be protected, T, and the lock, we define a single LockGuarded object which contains the object. That provides two big advantages: - it is immediately clear which data is protected by the lock - that data simply can't be accessed without holding the lock. --- diff --git a/pdns/lock.hh b/pdns/lock.hh index 0644502f87..ed4b07a6c3 100644 --- a/pdns/lock.hh +++ b/pdns/lock.hh @@ -148,3 +148,82 @@ private: std::unique_lock d_lock; }; + +template +class LockGuardedHolder +{ +public: + explicit LockGuardedHolder(T& value, std::mutex& mutex): d_lock(mutex), d_value(value) + { + } + + T& operator*() const noexcept { + return d_value; + } + + T* operator->() const noexcept { + return &d_value; + } + +private: + std::lock_guard d_lock; + T& d_value; +}; + +template +class LockGuardedTryHolder +{ +public: + explicit LockGuardedTryHolder(T& value, std::mutex& mutex): d_lock(mutex, std::try_to_lock), d_value(value) + { + } + + T& operator*() const { + if (!owns_lock()) { + throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired"); + } + return d_value; + } + + T* operator->() const { + if (!owns_lock()) { + throw std::runtime_error("Trying to access data protected by a mutex while the lock has not been acquired"); + } + return &d_value; + } + + operator bool() const noexcept { + return d_lock.owns_lock(); + } + + bool owns_lock() const noexcept { + return d_lock.owns_lock(); + } + +private: + std::unique_lock d_lock; + T& d_value; +}; + +template +class LockGuarded +{ +public: + explicit LockGuarded(T value): d_value(std::move(value)) + { + } + + LockGuardedTryHolder try_lock() + { + return LockGuardedTryHolder(d_value, d_mutex); + } + + LockGuardedHolder lock() + { + return LockGuardedHolder(d_value, d_mutex); + } + +private: + std::mutex d_mutex; + T d_value; +};