Reader-Writer Locks
In this lesson, we see what happens when we may want different kinds of locking on a data structure for different kinds of users.
We'll cover the following...
Another classic problem stems from the desire for a more flexible locking primitive that admits that different data structure accesses might require different kinds of locking. For example, imagine a number of concurrent list operations, including inserts and simple lookups. While inserts change the state of the list (and thus a traditional critical section makes sense), lookups simply read the data structure; as long as we can guarantee that no insert is on-going, we can allow many lookups to proceed concurrently. The special type of lock we will now develop to support this type of operation is known as a ...
typedef struct _rwlock_t {sem_t lock; // binary semaphore (basic lock)sem_t writelock; // allow ONE writer/MANY readersint readers; // #readers in critical section} rwlock_t;void rwlock_init(rwlock_t *rw) {rw->readers = 0;sem_init(&rw->lock, 0, 1);sem_init(&rw->writelock, 0, 1);}void rwlock_acquire_readlock(rwlock_t *rw) {sem_wait(&rw->lock);rw->readers++;if (rw->readers == 1) // first reader gets writelocksem_wait(&rw->writelock);sem_post(&rw->lock);}void rwlock_release_readlock(rwlock_t *rw) {sem_wait(&rw->lock);rw->readers--;if (rw->readers == 0) // last reader lets it gosem_post(&rw->writelock);sem_post(&rw->lock);}void rwlock_acquire_writelock(rwlock_t *rw) {sem_wait(&rw->writelock);}void rwlock_release_writelock(rwlock_t *rw) {sem_post(&rw->writelock);}
Explanation
The code is pretty simple. If some thread wants to update the data structure in question, it should call the new pair of synchronization operations: rwlock_acquire_writelock(), to acquire a write lock, and ...