Files
uLib/src/Core/Monitor.h
2026-03-25 11:04:37 +00:00

216 lines
6.5 KiB
C++

/*//////////////////////////////////////////////////////////////////////////////
// CMT Cosmic Muon Tomography project //////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova
All rights reserved
Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it >
------------------------------------------------------------------
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
//////////////////////////////////////////////////////////////////////////////*/
#ifndef U_CORE_MONITOR_H
#define U_CORE_MONITOR_H
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <utility>
namespace uLib {
/**
* @brief Mutex class wraps std::timed_mutex and is used for thread synchronization.
*/
class Mutex {
public:
Mutex() = default;
~Mutex() = default;
/** @brief Locks the mutex, blocking if necessary. */
void Lock() { m_Mutex.lock(); }
/** @brief Unlocks the mutex. */
void Unlock() { m_Mutex.unlock(); }
/** @brief Tries to lock the mutex without blocking. */
bool TryLock() { return m_Mutex.try_lock(); }
/** @brief Tries to lock the mutex within a timeout in milliseconds. */
bool TryLockFor(int timeout_ms) {
if (timeout_ms < 0) { Lock(); return true; }
return m_Mutex.try_lock_for(std::chrono::milliseconds(timeout_ms));
}
/** @brief RAII helper for scoped locking. */
class ScopedLock {
public:
ScopedLock(Mutex &mutex) : m_Mutex(mutex) { m_Mutex.Lock(); }
~ScopedLock() { m_Mutex.Unlock(); }
private:
Mutex &m_Mutex;
// Non-copyable
ScopedLock(const ScopedLock&) = delete;
ScopedLock& operator=(const ScopedLock&) = delete;
};
/** @brief Returns the underlying std::timed_mutex. */
std::timed_mutex& GetNative() { return m_Mutex; }
private:
std::timed_mutex m_Mutex;
// Non-copyable
Mutex(const Mutex &) = delete;
Mutex &operator=(const Mutex &) = delete;
};
namespace detail {
/** @brief Internal implementation for the ULIB_MUTEX_LOCK macros. */
class ScopedTimedLock {
public:
ScopedTimedLock(Mutex& mutex, int timeout_ms)
: m_RawMutex(nullptr), m_MutexWrapper(&mutex), m_Locked(false) {
m_Locked = m_MutexWrapper->TryLockFor(timeout_ms);
}
ScopedTimedLock(std::timed_mutex& mutex, int timeout_ms)
: m_RawMutex(&mutex), m_MutexWrapper(nullptr), m_Locked(false) {
if (timeout_ms < 0) { m_RawMutex->lock(); m_Locked = true; }
else m_Locked = m_RawMutex->try_lock_for(std::chrono::milliseconds(timeout_ms));
}
~ScopedTimedLock() {
if (m_Locked) {
if (m_RawMutex) m_RawMutex->unlock();
else if (m_MutexWrapper) m_MutexWrapper->Unlock();
}
}
operator bool() const { return m_Locked; }
void unlock() { if (m_Locked) {
if (m_RawMutex) m_RawMutex->unlock();
else if (m_MutexWrapper) m_MutexWrapper->Unlock();
m_Locked = false;
} }
private:
std::timed_mutex* m_RawMutex = nullptr;
Mutex* m_MutexWrapper = nullptr;
bool m_Locked;
// Non-copyable/movable to be safe in the 'for' loop
ScopedTimedLock(const ScopedTimedLock&) = delete;
ScopedTimedLock& operator=(const ScopedTimedLock&) = delete;
ScopedTimedLock(ScopedTimedLock&&) = default;
};
inline ScopedTimedLock makeScopedMutexLock(Mutex& mutex, int timeout_ms) {
return ScopedTimedLock(mutex, timeout_ms);
}
inline ScopedTimedLock makeScopedMutexLock(std::timed_mutex& mutex, int timeout_ms) {
return ScopedTimedLock(mutex, timeout_ms);
}
} // namespace detail
/**
* @brief Macro for block-scoped locking of a static mutex.
* @param timeout Timeout in ms (-1 for infinite).
*/
#define ULIB_STATIC_LOCK(timeout) \
static std::timed_mutex __ulib_static_mutex; \
for (auto __ulib_lock = uLib::detail::makeScopedMutexLock(__ulib_static_mutex, timeout); \
__ulib_lock; \
__ulib_lock.unlock())
/**
* @brief Macro for block-scoped locking of a provided mutex.
* @param mutex The uLib::Mutex or std::timed_mutex to lock.
* @param timeout Timeout in ms (-1 for infinite).
*/
#define ULIB_MUTEX_LOCK(mutex, timeout) \
for (auto __ulib_lock = uLib::detail::makeScopedMutexLock(mutex, timeout); \
__ulib_lock; \
__ulib_lock.unlock())
/**
* @brief RecursiveMutex class wraps std::recursive_timed_mutex.
*/
class RecursiveMutex {
public:
RecursiveMutex() = default;
~RecursiveMutex() = default;
/** @brief Locks the mutex, blocking if necessary. */
void Lock() { m_Mutex.lock(); }
/** @brief Unlocks the mutex. */
void Unlock() { m_Mutex.unlock(); }
/** @brief Tries to lock the mutex without blocking. */
bool TryLock() { return m_Mutex.try_lock(); }
/** @brief Tries to lock the mutex within a timeout in milliseconds. */
bool TryLockFor(int timeout_ms) {
if (timeout_ms < 0) { Lock(); return true; }
return m_Mutex.try_lock_for(std::chrono::milliseconds(timeout_ms));
}
/** @brief RAII helper for scoped locking. */
class ScopedLock {
public:
ScopedLock(RecursiveMutex &mutex) : m_Mutex(mutex) { m_Mutex.Lock(); }
~ScopedLock() { m_Mutex.Unlock(); }
private:
RecursiveMutex &m_Mutex;
ScopedLock(const ScopedLock&) = delete;
ScopedLock& operator=(const ScopedLock&) = delete;
};
private:
std::recursive_timed_mutex m_Mutex;
RecursiveMutex(const RecursiveMutex &) = delete;
RecursiveMutex &operator=(const RecursiveMutex &) = delete;
};
/**
* @brief Monitor class provides a base for objects that need thread-safe access.
*/
template <typename T>
class Monitor {
protected:
T* m_Resource;
Mutex m_Mutex;
public:
Monitor(T* resource) : m_Resource(resource) {}
virtual ~Monitor() { delete m_Resource; }
/** @brief Thread-safe access to the resource through a lambda. */
template <typename F>
auto Access(F f) -> decltype(f(*m_Resource)) {
Mutex::ScopedLock lock(m_Mutex);
return f(*m_Resource);
}
};
} // namespace uLib
#endif // U_CORE_MONITOR_H