Description: Below is an implementation of readwrite lock using mutex and condition variables. Note that, the implementation does not give any preference to waiting writers.
RwLock.h (Header File)
#include <pthread.h>
class RwLock
{
{
//nreaders = 0 , indicates no. reader/writer exists.
//nreaders > 0, indicates one or more read lock exists.
//nreaders=-1, indicates a write lock exists.
int nreaders;
pthread_mutex_t rw_mutex;
pthread_cond_t rw_cond;
public:
RwLock();
void getReadLock();
void getWriteLock();
void unLock();
~RwLock();
};
RwLock.C (Implementation of our ReadWrite Lock)
#include "RwLock.h"
RwLock :: RwLock()
{
nreaders = 0;
RwLock :: RwLock()
{
nreaders = 0;
// Initialize mutex and condition variable.
pthread_mutex_init(&rw_mutex, NULL);
pthread_cond_init(&rw_cond, NULL);
}
void RwLock :: getReadLock()
{
//Obtain Lock.
pthread_mutex_lock(&rw_mutex);
// If a WRITER exists(nreaders = -1)wait for signal from writer.
while(-1 == nreaders)
{
pthread_cond_wait(&rw_cond, &rw_mutex);
}
// Increment no. of reader
nreaders++;
pthread_mutex_init(&rw_mutex, NULL);
pthread_cond_init(&rw_cond, NULL);
}
void RwLock :: getReadLock()
{
//Obtain Lock.
pthread_mutex_lock(&rw_mutex);
// If a WRITER exists(nreaders = -1)wait for signal from writer.
while(-1 == nreaders)
{
pthread_cond_wait(&rw_cond, &rw_mutex);
}
// Increment no. of reader
nreaders++;
//Unlock the mutex.
pthread_mutex_unlock(&rw_mutex);
}
void RwLock :: getWriteLock()
{
//Obtain Lock
pthread_mutex_lock(&rw_mutex);
// If nreader is != 0 it means either a reader or writer is present. wait for signal from reader/writer (do it in a loop)
while(0 != nreaders)
{
pthread_cond_wait(&rw_cond, &rw_mutex);
}
// Set nreader = -1 indicating a writer is present.
nreaders = -1;
// Unlock the mutex.
pthread_mutex_unlock(&rw_mutex);
}
void RwLock :: unLock()
{
// Obtain Lock.
pthread_mutex_lock(&rw_mutex);
if(0 < nreaders)
{
// One of the readers is done. decrement readers count.
nreaders--;
if(0 == nreaders)
{
// Last reader is done.
pthread_cond_broadcast(&rw_cond);
}
}
else if(-1 == nreaders)
{
// A writer is done. set nreaders to 0 indicating no reader/writer exists.
nreaders = 0;
pthread_cond_broadcast(&rw_cond);
}
pthread_mutex_unlock(&rw_mutex);
}
void RwLock :: getWriteLock()
{
//Obtain Lock
pthread_mutex_lock(&rw_mutex);
// If nreader is != 0 it means either a reader or writer is present. wait for signal from reader/writer (do it in a loop)
while(0 != nreaders)
{
pthread_cond_wait(&rw_cond, &rw_mutex);
}
// Set nreader = -1 indicating a writer is present.
nreaders = -1;
// Unlock the mutex.
pthread_mutex_unlock(&rw_mutex);
}
void RwLock :: unLock()
{
// Obtain Lock.
pthread_mutex_lock(&rw_mutex);
if(0 < nreaders)
{
// One of the readers is done. decrement readers count.
nreaders--;
if(0 == nreaders)
{
// Last reader is done.
pthread_cond_broadcast(&rw_cond);
}
}
else if(-1 == nreaders)
{
// A writer is done. set nreaders to 0 indicating no reader/writer exists.
nreaders = 0;
pthread_cond_broadcast(&rw_cond);
}
// Unlock the mutex.
pthread_mutex_unlock(&rw_mutex);
}
RwLock :: ~RwLock()
{
// Destroy condition variable and mutex.
pthread_mutex_destroy(&rw_mutex);
pthread_cond_destroy(&rw_cond);
}
Below is a sample program that uses this implementation and output obtained.
pthread_mutex_unlock(&rw_mutex);
}
RwLock :: ~RwLock()
{
// Destroy condition variable and mutex.
pthread_mutex_destroy(&rw_mutex);
pthread_cond_destroy(&rw_cond);
}
Below is a sample program that uses this implementation and output obtained.
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
#include<iostream>
#include "RwLock.h"
using namespace std;
RwLock rwlock;
void* reader(void* arg)
{
cout << "Obtaining read lock." << endl;
rwlock.getReadLock();
cout << "Obtained read lock." << endl;
sleep(5);
cout << "Releasing read lock." << endl;
rwlock.unLock();
cout << "Released read lock." << endl;
}
void* writer(void* arg)
{
cout << "Obtaining write lock." << endl;
rwlock.getWriteLock();
cout << "Obtained write lock." << endl;
sleep(4);
cout << "Releasing write lock." << endl;
rwlock.unLock();
cout << "Released write lock." << endl;
}
int main(int argc, char** argv)
{
pthread_t r1,r2,r3,w1,w2;
int res;
cout << endl;
res = pthread_create(&r1, NULL, reader, NULL);
if(0 != res)
{
cout << "Failed to start thread." << endl;
exit(1);
}
res = pthread_create(&r2, NULL, reader, NULL);
if(0 != res)
{
cout << "Failed to start thread." << endl;
exit(1);
}
sleep(1);
res = pthread_create(&w1, NULL, writer, NULL);
if(0 != res)
{
cout << "Failed to start thread." << endl;
exit(1);
}
res = pthread_create(&w2, NULL, writer, NULL);
if(0 != res)
{
cout << "Failed to start thread." << endl;
exit(1);
}
pthread_exit(NULL);
}
#include<pthread.h>
#include<stdlib.h>
#include<iostream>
#include "RwLock.h"
using namespace std;
RwLock rwlock;
void* reader(void* arg)
{
cout << "Obtaining read lock." << endl;
rwlock.getReadLock();
cout << "Obtained read lock." << endl;
sleep(5);
cout << "Releasing read lock." << endl;
rwlock.unLock();
cout << "Released read lock." << endl;
}
void* writer(void* arg)
{
cout << "Obtaining write lock." << endl;
rwlock.getWriteLock();
cout << "Obtained write lock." << endl;
sleep(4);
cout << "Releasing write lock." << endl;
rwlock.unLock();
cout << "Released write lock." << endl;
}
int main(int argc, char** argv)
{
pthread_t r1,r2,r3,w1,w2;
int res;
cout << endl;
res = pthread_create(&r1, NULL, reader, NULL);
if(0 != res)
{
cout << "Failed to start thread." << endl;
exit(1);
}
res = pthread_create(&r2, NULL, reader, NULL);
if(0 != res)
{
cout << "Failed to start thread." << endl;
exit(1);
}
sleep(1);
res = pthread_create(&w1, NULL, writer, NULL);
if(0 != res)
{
cout << "Failed to start thread." << endl;
exit(1);
}
res = pthread_create(&w2, NULL, writer, NULL);
if(0 != res)
{
cout << "Failed to start thread." << endl;
exit(1);
}
pthread_exit(NULL);
}
Output:
Obtaining read lock.
Obtained read lock.
Obtaining read lock.
Obtained read lock. /*Two read locks obtained*/
Obtaining write lock.
Obtaining write lock. /*Two threads waiting for write lock*/
Releasing read lock.
Released read lock.
Releasing read lock.
Released read lock. /*Two read locks are released*/
Obtained write lock.
Releasing write lock.
Released write lock. /*A thread first gets write lock and releases it*/
Obtained write lock. /*Second thread gets the write lock*/
Releasing write lock.
Released write lock.
Obtained read lock.
Obtaining read lock.
Obtained read lock. /*Two read locks obtained*/
Obtaining write lock.
Obtaining write lock. /*Two threads waiting for write lock*/
Releasing read lock.
Released read lock.
Releasing read lock.
Released read lock. /*Two read locks are released*/
Obtained write lock.
Releasing write lock.
Released write lock. /*A thread first gets write lock and releases it*/
Obtained write lock. /*Second thread gets the write lock*/
Releasing write lock.
Released write lock.
No comments:
Post a Comment