boost::shared_mutex or std::shared_mutex (C++17) can be used for single writer, multiple reader access. As an educational exercise, I put together a simple implementation that uses spinlocking and has other limitations (eg. fairness policy), but is obviously not intended to be used in real applications.
The idea is that the mutex keeps a reference count that is zero if no thread holds the lock. If > 0, the value represents the number of readers that have access. If -1, a single writer has access.
Is this a correct implementation (in particular with the used, minimal, memory orderings) that is free of data races ?
#include <atomic> class my_shared_mutex { std::atomic<int> refcount{0}; public: void lock() // write lock { int val; do { val = 0; // Can only take a write lock when refcount == 0 } while (!refcount.compare_exchange_weak(val, -1, std::memory_order_acquire)); // can memory_order_relaxed be used if only a single thread takes write locks ? } void unlock() // write unlock { refcount.store(0, std::memory_order_release); } void lock_shared() // read lock { int val; do { do { val = refcount.load(std::memory_order_relaxed); } while (val == -1); // spinning until the write lock is released } while (!refcount.compare_exchange_weak(val, val+1, std::memory_order_acquire)); } void unlock_shared() // read unlock { // This must be a release operation (see answer) refcount.fetch_sub(1, std::memory_order_relaxed); } };