> my use-case is a structure that receives many read requests and a few writes, clearly justifying using a rwlock instead of a mutex, but I may want some of the reads to block until a write has happened, which means I need a condition variable
First, if readers encounter an rwlock locked by a writer, they will suspend until the writer releases the rwlock (if --disable-simple-mutex is set, which is not set by default).
For this specific purpose(especially if "some", not "all" of the readers should block), what I came up with in my mind first is the following. It looks fine except for a seemingly complex structure that uses multiple synchronization objects.
void reader() {
while (1) {
if (work_queue.is_empty() and I_AM_SOME_OF_READERS()) {
// 1. Internally ABT_self_suspend()-like mechanism needs
// to take a lock (even if it is in the readers' lock)
// since multiple readers might access the same data
// structure (for example, a user-maintained
// suspended ULT list).
// 2. Anyway this path is not performance sensitive
ABT_mutex_lock(mutex);
ABT_cond_wait(cond, mutex);
ABT_mutex_unlock(mutex);
// Now someone woke me up after pushing work.
}
ABT_rwlock_rdlock(rwlock);
if (!work_queue.is_empty())
; // Do real work.
ABT_rwlock_unlock(rwlock);
}
}
void writer() {
ABT_rwlock_wrlock(rwlock);
work_queue.push_work(work);
// You do not need to take a mutex to call ABT_cond_broadcast.
// It is fine even if there's no waiter.
ABT_cond_broadcast(cond);
ABT_rwlock_unlock(rwlock);
}