/* Icinga 2 | (c) 2019 Icinga GmbH | GPLv2+ */ #ifndef ATOMIC_H #define ATOMIC_H #include #include #include #include #include namespace icinga { /** * Like std::atomic, but enforces usage of its only safe constructor. * * "The default-initialized std::atomic does not contain a T object, * and its only valid uses are destruction and * initialization by std::atomic_init, see LWG issue 2334." * -- https://en.cppreference.com/w/cpp/atomic/atomic/atomic * * @ingroup base */ template class Atomic : public std::atomic { public: /** * The only safe constructor of std::atomic#atomic * * @param desired Initial value */ inline Atomic(T desired) : std::atomic(desired) { } }; /** * Accumulates time durations atomically. * * @ingroup base */ class AtomicDuration { public: using Clock = std::chrono::steady_clock; AtomicDuration& operator+=(const Clock::duration&) noexcept; /** * @return The total accumulated time in seconds */ template operator T() const noexcept { return std::chrono::duration(Clock::duration(m_Sum.load(std::memory_order_relaxed))).count(); } private: Atomic m_Sum {0}; }; /** * Wraps any T into a std::atomic-like interface that locks using a mutex. * * In contrast to std::atomic, Locked is also valid for types that are not trivially copyable. * In case T is trivially copyable, std::atomic is almost certainly the better choice. * * @ingroup base */ template class Locked { public: inline T load() const { std::unique_lock lock(m_Mutex); return m_Value; } inline void store(T desired) { std::unique_lock lock(m_Mutex); m_Value = std::move(desired); } private: mutable std::mutex m_Mutex; T m_Value; }; /** * Type alias for std::atomic if possible, otherwise Locked is used as a fallback. * * @ingroup base */ template using AtomicOrLocked = #if defined(__GNUC__) && __GNUC__ < 5 // GCC does not implement std::is_trivially_copyable until version 5. typename std::conditional::value || std::is_pointer::value, std::atomic, Locked>::type; #else /* defined(__GNUC__) && __GNUC__ < 5 */ typename std::conditional::value, std::atomic, Locked>::type; #endif /* defined(__GNUC__) && __GNUC__ < 5 */ } #endif /* ATOMIC_H */