I'm looking for a good reader/writer lock in C++. We have a use case of a single infrequent writer and many frequent readers and would like to optimize for this. Preferable I would like a cross-platform solution, however a Windows only one would be acceptable.
13 Answers
Since C++ 14 (VS2015) you can use the standard:
#include <shared_mutex>
typedef std::shared_mutex Lock;
typedef std::unique_lock< Lock > WriteLock; // C++ 11
typedef std::shared_lock< Lock > ReadLock; // C++ 14
Lock myLock;
void ReadFunction()
{
ReadLock r_lock(myLock);
//Do reader stuff
}
void WriteFunction()
{
WriteLock w_lock(myLock);
//Do writer stuff
}
For older compiler versions and standards you can use boost to create a read-write lock:
#include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp>
typedef boost::shared_mutex Lock;
typedef boost::unique_lock< Lock > WriteLock;
typedef boost::shared_lock< Lock > ReadLock;

- 77
- 9

- 48,127
- 24
- 147
- 185
-
3This looks like this will still starve the write thread given tons of read threads and one write thread. – Brian Yeh Nov 16 '20 at 18:03
-
2You don't need 3 separate locks -- std::shared_mutex already supports ReadWriteLock functionality by itself. To acquire an exclusive (writer) lock, use ".lock()", to acquire a shared (reader) lock use ".lock_shared()" – Gavin Ray Sep 11 '22 at 16:05
-
@GavinRay Yes, but with using those structs, you get wrapping RAII objects that will ensure proper resource management and ensure that the locks are actually released in the end of the scope. – Yochai Timmer Sep 11 '22 at 16:40
-
Oh I see, so they're alternatives to using std::lock_guard in each function where you acquire locks? – Gavin Ray Sep 11 '22 at 16:42
Newer versions of boost::thread have read/write locks (1.35.0 and later, apparently the previous versions did not work correctly).
They have the names shared_lock
, unique_lock
, and upgrade_lock
and operate on a shared_mutex
.

- 5,549
- 7
- 43
- 55

- 35,641
- 17
- 67
- 94
-
3
-
1The thread library underwent a massive overhaul from 1.34 -> 1.35 so be aware of this when upgrading. Some breaking API changes were made, but they wont affect most people very much. The new version is more in line with the proposed C++0x library interface, which is a good thing in the long run. – Greg Rogers Oct 28 '08 at 18:46
-
We don't use most of the threading library to heavily, but we do use it for our locks. I did bust into the details to specialize lock_ops in one place so I could use scoped_lock with my type. I agree that in the long run we want the more standard implementation. – Matt Price Oct 28 '08 at 18:51
-
If you're lucky enough to have C++14 or C++17 available, you can also use [`shared_timed_mutex`](https://en.cppreference.com/w/cpp/thread/shared_timed_mutex) and a matching [`shared_lock`](https://en.cppreference.com/w/cpp/thread/shared_lock). – Jan Kundrát Oct 22 '18 at 16:40
Using standard pre-tested, pre-built stuff is always good (for example, Boost as another answer suggested), but this is something that's not too hard to build yourself. Here's a dumb little implementation pulled out from a project of mine:
#include <pthread.h>
struct rwlock {
pthread_mutex_t lock;
pthread_cond_t read, write;
unsigned readers, writers, read_waiters, write_waiters;
};
void reader_lock(struct rwlock *self) {
pthread_mutex_lock(&self->lock);
if (self->writers || self->write_waiters) {
self->read_waiters++;
do pthread_cond_wait(&self->read, &self->lock);
while (self->writers || self->write_waiters);
self->read_waiters--;
}
self->readers++;
pthread_mutex_unlock(&self->lock);
}
void reader_unlock(struct rwlock *self) {
pthread_mutex_lock(&self->lock);
self->readers--;
if (self->write_waiters)
pthread_cond_signal(&self->write);
pthread_mutex_unlock(&self->lock);
}
void writer_lock(struct rwlock *self) {
pthread_mutex_lock(&self->lock);
if (self->readers || self->writers) {
self->write_waiters++;
do pthread_cond_wait(&self->write, &self->lock);
while (self->readers || self->writers);
self->write_waiters--;
}
self->writers = 1;
pthread_mutex_unlock(&self->lock);
}
void writer_unlock(struct rwlock *self) {
pthread_mutex_lock(&self->lock);
self->writers = 0;
if (self->write_waiters)
pthread_cond_signal(&self->write);
else if (self->read_waiters)
pthread_cond_broadcast(&self->read);
pthread_mutex_unlock(&self->lock);
}
void rwlock_init(struct rwlock *self) {
self->readers = self->writers = self->read_waiters = self->write_waiters = 0;
pthread_mutex_init(&self->lock, NULL);
pthread_cond_init(&self->read, NULL);
pthread_cond_init(&self->write, NULL);
}
pthreads
not really being Windows-native, but the general idea is here. This implementation is slightly biased towards writers (a horde of writers can starve readers indefinitely); just modify writer_unlock
if you'd rather the balance be the other way around.
Yes, this is C and not C++. Translation is an exercise left to the reader.
Edit
Greg Rogers pointed out that the POSIX standard does specify pthread_rwlock_*
. This doesn't help if you don't have pthreads
, but it stirred my mind into remembering: Pthreads-w32 should work! Instead of porting this code to non-pthreads
for your own use, just use Pthreads-w32 on Windows, and native pthreads
everywhere else.

- 198,619
- 38
- 280
- 391
-
3I'm curious as to why you reimplemented pthread_rwlock_(rd/wr)(un)lock on top of pthread_mutex_t instead of just using the native pthread API. – Greg Rogers Oct 28 '08 at 18:54
-
Because I could / for fun. This project was a bit of a testbed for various locking facilities of mine. Also, it's useful as a demonstration now, right? – ephemient Oct 28 '08 at 19:11
-
Unfortunately NOT an implementation that is usable. Potential busy Spin wait here: while (self->writers || self->write_waiters); Plus you gave a C solution to a C++ question. – Martin York Oct 28 '08 at 19:15
-
It doesn't spin: the `while` modifies the `do pthread_cond_wait` on the line immediately above it. There are no exceptions in C. (True, I don't handle error conditions, but those aren't exceptions.) – ephemient Oct 28 '08 at 19:19
-
3In the reader_unlock function, you signal the writers, even if there are readers currently reading the data. It is better to add to your condition if (self->readers == 0 && self->write_waiters) ... – Anna Jan 11 '10 at 13:18
-
Like I mentioned, "This implementation is slightly biased towards writers (a horde of writers can starve readers indefinitely); just modify `writer_unlock` if you'd rather the balance be the other way around." – ephemient Jan 11 '10 at 14:39
-
1I'm trying to make a different point here. If there are readers still reading, there is no point in signaling the writers, as the writers will not start working anyway, and just catch the lock and take useless time. This is a matter of minor inefficiency, not of priority. – Anna Jan 11 '10 at 15:04
-
2What do mean there is no point? A new writer can happily take the lock even when there are readers waiting for the lock as long as nobody is actually holding the lock, and proceed to do work. If you have a continuous stream of readers and don't want occasional short writers to be blocked by them, this is the better balance. – ephemient Jan 11 '10 at 16:28
Whatever you decide to use, benchmark your work load against simple locks, as read/write locks tend to be 3-40x slower than simple mutex, when there is no contention.
Here is some reference

- 5,790
- 1
- 20
- 21
-
-
1
-
To read more on this: C++ Concurrency in Action 2nd. ed. by Anthony Williams, chapter 3.3.2 and later 8-th. – marcinj Aug 06 '19 at 07:05
-
Simple test shows that r/w locking might really be slower in some cases: https://coliru.stacked-crooked.com/a/dce6e59b0f01d513 – marcinj Aug 06 '19 at 09:24
C++17 supports std::shared_mutex
. It is supported in MSVC++ 2015 and 2017.

- 13,865
- 7
- 86
- 158
-
And in C++14, there is the [`shared_timed_mutex`](https://en.cppreference.com/w/cpp/thread/shared_timed_mutex) and a matching [`shared_lock`](https://en.cppreference.com/w/cpp/thread/shared_lock). – Jan Kundrát Oct 22 '18 at 16:39
Edit: The MSDN Magazine link isn't available anymore. The CodeProject article is now available on https://www.codeproject.com/Articles/32685/Testing-reader-writer-locks and sums it up pretty nicely. Also I found a new MSDN link about Compound Synchronisation Objects.
There is an article about reader-writer locks on MSDN that presents some implementations of them. It also introduces the Slim reader/writer lock, a kernel synchronisation primitive introduced with Vista. There's also a CodeProject article about comparing different implementations (including the MSDN article's ones).

- 6,468
- 9
- 43
- 53
-
My experience with the slim rw lock is that it's super fast compared to the ones based on mutexes and signals. – Laserallan Mar 02 '09 at 14:59
-
The annoying thing is that to use it you have to write run-time OS detection and use function pointers or a virtual class to select a locking strategy. Not practical to ignore XP yet. – Zan Lynx Aug 31 '10 at 04:06
-
yes, you're right, Zan. Just wanted to mention it, in case someone finds the question and can use it. – vividos Aug 31 '10 at 07:32
-
Intel Thread Building Blocks also provide a couple of rw_lock variants:
http://www.threadingbuildingblocks.org/
They have a spin_rw_mutex for very short periods of contention and a queueing_rw_mutex for longer periods of contention. The former can be used in particularly performance sensitive code. The latter is more comparable in performance to that provided by Boost.Thread or directly using pthreads. But profile to make sure which one is a win for your access patterns.

- 29,632
- 7
- 85
- 107
-
Er, not that I would necessarily recommend bringing in all of TBB just to get rw_locks. – Edward Kmett Nov 07 '08 at 12:52
-
2Instead of choosing the variant based on "particularly performance sensitive code", the choice should be based on the average duration the lock will be held. If the lock is held only for the reading of a few integers and released afterwards, then spin will be appropriate. Otherwise queueing will be appropriate. – rwong Feb 27 '13 at 06:58
-
@rwong I agree completely. I intended to convey the appropriate time windows in the previous sentence and perhaps made it sound more wishy-washy than it is. ;) – Edward Kmett Feb 28 '13 at 02:11
I can recommend the ACE library, which provides a multitude of locking mechanisms and is ported to various platforms.
Depending on the boundary conditions of your problem, you may find the following classes useful:
ACE_RW_Process_Mutex
ACE_Write_Guard
andACE_Read_Guard
ACE_Condition
-
I wouldn't mind, but I don't think I can get the ACE libraries into our build right now. I've used them in the past and they are great. – Matt Price Oct 28 '08 at 19:40
-
1Anything that has to do with ACE is bad. it's an ancient code base, poorly documented and impossible to get into. Avoid infecting your code with it at any cost. – shoosh Jul 28 '11 at 08:53
-
I completely agree with @shoosh: Even the link provided in the answer 404s :-( The project I'm working on (which started in the late 17th century) uses it, so I'll have no other choice but to make do, but for any moderately fresh code: Stay away from ACE at all costs. – ssc Jun 11 '14 at 12:52
-
On the subject of how contemporary ACE is, see also [this](http://stackoverflow.com/q/992069/217844) and [this](http://stackoverflow.com/q/8368493/217844) SO question. – ssc Jun 11 '14 at 13:04
Boost.Thread has since release 1.35.0 already supports reader-writer locks. The good thing about this is that the implementation is greatly cross-platform, peer-reviewed, and is actually a reference implementation for the upcoming C++0x standard.

- 3,446
- 1
- 20
- 14
-
1Yeah, almost -- but Boost.Thread being the basis for C++0x threading wasn't part of the accepted answer above. Consider this additional information. :) – Dean Michael Oct 29 '08 at 01:02
http://www.codeproject.com/KB/threads/ReaderWriterLock.aspx
Here is a good and lightweight implementation suitable for most tasks.

- 29,378
- 23
- 95
- 156
Multiple-Reader, Single-Writer Synchronization Lock Class for Win32 by Glenn Slayde

- 6,558
- 4
- 47
- 75
#include <shared_mutex>
class Foo {
public:
void Write() {
std::unique_lock lock{mutex_};
// ...
}
void Read() {
std::shared_lock lock{mutex_};
// ...
}
private:
std::shared_mutex mutex_;
};

- 121
- 4
You could copy Sun's excellent ReentrantReadWriteLock. It includes features such as optional fairness, lock downgrading, and of course reentrancy.
Yes it's in Java, but you can easily read and transpose it to C++, even if you don't know any Java. The documentation I linked to contains all the behavioral properties of this implementation so you can make sure it does what you want.
If nothing else, it's a guide.

- 81,399
- 26
- 107
- 114
-
2Java and C++ are soo different in style thats probably not a good idea. Java threading builtin to the language C++ does not. The code (directly translated) is not exception safe. – Martin York Oct 28 '08 at 18:44
-
1That's completely untrue. In fact, Java's intstruction reordering rules are *more* permissive than most C++ compilers, which means it's *safer*. Your statement that "threading is in the language" is moot because the thread behavior is clearly defined as a standard "mutex" and "lock" system which all C++ threading systems that I've ever used also have, so the translation would indeed be simple. – Jason Cohen Dec 20 '09 at 03:11
-
3I think you're missing the point of exception-safety. Java doesn't use RAII idiomatically, and C++ doesn't have `finally`, so a direct translation from Java to C++ is a bad idea in the presence of excepions. – Tom Jan 23 '10 at 00:52