I was trying to implement read/write lock using mutex only (just for learning). Just when i thought i have covered all corner cases (as the program worked with variety of combinations), i have realized, i ignored the fact (as it worked in ubuntu) that, the mutex should be freed by the owner of the thread. Below is my implementation,
class rw_lock_t{
int NoOfReaders;
int NoOfWriters, NoOfWritersWaiting;
pthread_mutex_t class_mutex;
pthread_cond_t class_cond;
pthread_mutex_t data_mutex;
public:
rw_lock_t()
: NoOfReaders(0),
NoOfWriters(0), NoOfWritersWaiting(0)
{
pthread_mutex_init(&class_mutex, NULL);
pthread_mutex_init(&data_mutex, NULL);
pthread_cond_init(&class_cond, NULL);
}
void r_lock()
{
pthread_mutex_lock(&class_mutex);
//while(NoOfWriters!=0 || NoOfWritersWaiting!=0) //Writer Preference
while(NoOfWriters!=0)
{
pthread_cond_wait(&class_cond, &class_mutex);
}
if(NoOfReaders==0)
{
pthread_mutex_unlock(&class_mutex);
pthread_mutex_lock(&data_mutex);
pthread_mutex_lock(&class_mutex);
NoOfReaders++;
pthread_mutex_unlock(&class_mutex);
}
else if(NoOfReaders>0) //Already Locked
{
NoOfReaders++;
pthread_mutex_unlock(&class_mutex);
}
}
void w_lock()
{
pthread_mutex_lock(&class_mutex);
NoOfWritersWaiting++;
while(NoOfReaders!=0 && NoOfWriters!=0)
{
pthread_cond_wait(&class_cond, &class_mutex);
}
pthread_mutex_unlock(&class_mutex);
pthread_mutex_lock(&data_mutex);
pthread_mutex_lock(&class_mutex);
NoOfWritersWaiting--; NoOfWriters++;
pthread_mutex_unlock(&class_mutex);
}
void r_unlock()
{
pthread_mutex_lock(&class_mutex);
NoOfReaders--;
if(NoOfReaders==0)
pthread_mutex_unlock(&data_mutex);
pthread_mutex_unlock(&class_mutex);
pthread_cond_signal(&class_cond);
}
void w_unlock()
{
pthread_mutex_lock(&class_mutex);
NoOfWriters--;
if(NoOfWriters==0)
pthread_mutex_unlock(&data_mutex);
pthread_mutex_unlock(&class_mutex);
pthread_cond_signal(&class_cond);
}
};
My question now is, what is the best way (minimal change) to rectify. Semaphore is definitely the idle choice, but I thought of solutions as below
Solution#1
1) I will have a dedicated thread, just to lock/unlock the mutex for read case.
2) This thread will be waiting on a condition variable to get signal from r_lock or r_unlock.
3) r_lock and r_unlock will instead of doing "pthread_mutex_lock/unlock(&data_mutex);", will signal the dedicated thread to lock instead.
4) I have to remember many facts for this implementation,
The signaling and actual locking are two different events, so might need synchronization.
Will need a mutex+condVariable+thread and more synchronization extra.
Update: Solution#2
1) The thread who did the actual locking will keep its tid globally.
2) whenever a thread unlocks will make sure the check equality with the global tid.
3) If matches will wait for "NoOfReaders==0" condition and unlock it.
So, is there a better way in which the program can be rectified.