#include <mutex>
#include <shared_mutex>
+/*
+ This file provides several features around locks:
+
+ - LockGuarded and SharedLockGuarded provide a way to wrap any data structure as
+ protected by a lock (mutex or shared mutex), while making it immediately clear
+ which data is protected by that lock, and preventing any access to the data without
+ holding the lock.
+
+ For example, to protect a set of integers with a simple mutex:
+
+ LockGuarded<std::set<int>> d_data;
+
+ or with a shared mutex instead:
+
+ SharedLockGuarded<std::set<int>> d_data;
+
+ Then the only ways to access the data is to call the lock(), read_only_lock() or try_lock() methods
+ for the simple case, or the read_lock(), write_lock(), try_read_lock() or try_write_lock() for the
+ shared one.
+ Doing so will return a "holder" object, which provides access to the protected data, checking that
+ the lock has really been acquired if needed (try_ cases). The data might be read-only if read_lock(),
+ try_read_lock() or read_only_lock() was called. Access is provided by dereferencing the holder object
+ via '*' or '->', allowing a quick-access syntax:
+
+ return d_data.lock()->size();
+
+ Or when the lock needs to be kept for a bit longer:
+
+ {
+ auto data = d_data.lock();
+ data->clear();
+ data->insert(42);
+ }
+
+ - ReadWriteLock is a very light wrapper around a std::shared_mutex.
+ It used to be useful as a RAII wrapper around pthread_rwlock, but since
+ C++17 we don't actually that, so it's mostly there for historical
+ reasons.
+
+ - ReadLock, WriteLock, TryReadLock and TryWriteLock are there as RAII
+ objects allowing to take a lock and be sure that it will always be unlocked
+ when we exit the block, even with a unforeseen exception.
+ They are light wrappers around std::unique_lock and std::shared_lock
+ since C++17.
+
+ Note that while the use of a shared mutex might be very efficient when the data
+ is predominantly concurrently accessed for reading by multiple threads and not
+ often written to (although if it is almost never updated our StateHolder in
+ sholder.hh might be a better fit), it is significantly more expensive than
+ a regular mutex, so that one might be a better choice if the contention is
+ low. It is wise to start with a regular mutex and actually measure the contention
+ under load before switching to a shared mutex.
+ */
+
class ReadWriteLock
{
public: