abstraction: lock that distinguishes readers/writers
operations:
pthread_rwlock_t rwlock;
pthread_rwlock_init(&rwlock, NULL /* attributes */);
...
pthread_rwlock_rdlock(&rwlock);
... /* read shared data */
pthread_rwlock_unlock(&rwlock);
pthread_rwlock_wrlock(&rwlock);
... /* read+write shared data */
pthread_rwlock_unlock(&rwlock);
...
pthread_rwlock_destroy(&rwlock);
|
|
|
|
|
|
mutex_t lock;
unsigned int readers, writers;
/* condition, signal when writers becomes 0 */
cond_t ok_to_read_cv;
/* condition, signal when readers + writers becomes 0 */
cond_t ok_to_write_cv;
ReadLock() {
mutex_lock(&lock);
while (writers != 0) {
cond_wait(&ok_to_read_cv, &lock);
}
++readers;
mutex_unlock(&lock);
}
ReadUnlock() {
mutex_lock(&lock);
--readers;
if (readers == 0) {
cond_signal(&ok_to_write_cv);
}
mutex_unlock(&lock);
}
WriteLock() {
mutex_lock(&lock);
while (readers + writers != 0) {
cond_wait(&ok_to_write_cv);
}
++writers;
mutex_unlock(&lock);
}
WriteUnlock() {
mutex_lock(&lock);
--writers;
[[cond_signal(&ok_to_write_cv);]{.fragment fragment-index=5 .custom .myem-only}]{.fragment fragment-index=6 .custom .myem-only}
[[cond_broadcast(&ok_to_read_cv);]{.fragment fragment-index=4 .custom .myem-only}]{.fragment fragment-index=6 .custom .myem-only}
mutex_unlock(&lock);
}
lock to protect shared state
state: number of active readers, writers
conditions to wait for (no readers or writers, no writers)
broadcast — wakeup all readers when no writers
wakeup a single writer when no readers or writers
problem: wakeup readers first or writer first?
this solution: wake them all up and they fight! inefficient!
mutex_t lock; cond_t ok_to_read_cv; cond_t ok_to_write_cv;
int readers = 0, writers = 0;
int waiting_writers = 0;
ReadLock() {
mutex_lock(&lock);
while (writers != 0
|| waiting_writers != 0) {
cond_wait(&ok_to_read_cv, &lock);
}
++readers;
mutex_unlock(&lock);
}
ReadUnlock() {
mutex_lock(&lock);
--readers;
if (readers == 0) {
cond_signal(&ok_to_write_cv);
}
mutex_unlock(&lock);
}
WriteLock() {
mutex_lock(&lock);
++waiting_writers;
while (readers + writers != 0) {
cond_wait(&ok_to_write_cv, &lock);
}
--waiting_writers;
++writers;
mutex_unlock(&lock);
}
WriteUnlock() {
mutex_lock(&lock);
--writers;
if (waiting_writers != 0) {
cond_signal(&ok_to_write_cv);
} else {
cond_broadcast(&ok_to_read_cv);
}
mutex_unlock(&lock);
}
...
int waiting_readers = 0;
ReadLock() {
mutex_lock(&lock);
++waiting_readers;
while (writers != 0) {
cond_wait(&ok_to_read_cv, &lock);
}
--waiting_readers;
++readers;
mutex_unlock(&lock);
}
ReadUnlock() {
...
if (waiting_readers == 0) {
cond_signal(&ok_to_write_cv);
}
}
WriteLock() {
mutex_lock(&lock);
while (waiting_readers +
readers + writers != 0) {
cond_wait(&ok_to_write_cv);
}
++writers;
mutex_unlock(&lock);
}
WriteUnlock() {
mutex_lock(&lock);
--writers;
if (readers == 0 && waiting_readers == 0) {
cond_signal(&ok_to_write_cv);
} else {
cond_broadcast(&ok_to_read_cv);
}
mutex_unlock(&lock);
}
can use monitors to implement lots of lock policies
want \(X\) to go first/last — add extra variables
need way to write condition ‘‘you can go now’’