Solution 1, over-constrained: we have one lock (access) for
read and write.
Reader() {
while (true) {
lock(&access);
Read(database);
unlock(&access);
}
}
Writer() {
while (true) {
lock(&access);
Write(database);
unlock(&access);
}
}
Problem: only 1 reader at a time can access the database.
Solution 2: introduce a counter for the number of readers. The first reader locks the access to the database and the last one unlocks it. We need to protect the number of readers also.
Writer() { /* same as before */ }
Reader() {
while (true) {
lock(&read_mutex);
reader_nr ++;
if (reader_nr == 1)
lock(&access);
unlock(&read_mutex);
Read(database);
lock(&read_mutex);
reader_nr --;
if (reader_nr == 0) {
unlock(&access);
unlock(&read_mutex);
}
}
Problem: the writers may never get through.
Solution 3: also count the number of writers and the number of writers that are waiting. It works for the case where the number of readers is much higher than the number of writers, but the writers have priority over the readers - while there is any writer attempting to access the database, no reader can pass through.
Reader() {
while (true) {
good_to_go = 0; // Local variable !!
while (!good_to_go) {
lock(&mutex);
if (writer_nr == 0 &&
waiting
== 0) {
reader_nr ++;
good_to_go = 1;
}
unlock(&mutex);
}
Read(database);
lock(&mutex);
reader_nr --;
unlock(&mutex);
}
}
Writer() {
while (true) {
good_to_go = 0; // Local variable !!
signaled = 0; // Local variable
too.
while (!good_to_go) {
lock(&mutex);
if (reader_nr == 0 &&
writer_nr
== 0) {
writer_nr ++;
if (signaled)
waiting--;
good_to_go = 1;
}
else if (!signaled) {
signaled = 1;
waiting++;
}
unlock(&mutex);
}
Write(database);
lock(&mutex);
writer_nr --;
unlock(&mutex);
}
}
Example of code: reader_writer.cc
Read-Write Locks in Pthread
They are locked that can be locked in 2 ways: in read mode, in which case they can be shared, or in write mode, which is exclusive.
pthread_rwlock_t lock; pthread_rwlock_init(&lock, NULL); pthread_rwlock_rdlock(&lock); pthread_rwlock_wrlock(&lock); pthread_rwlock_unlock(&lock);