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 combin
You do not need a separate mutex "for data"; the whole construct will serve as the data lock, if its internal logic is correct. Instead, you could use two separate condition variables for readers and for writers, so that you can broadcast all waiting readers without affecting waiting writers. The code is below; you can also see that it's simpler this way. Besides, I added a destructor and fixed a bug in w_lock: the condition to wait should be (NoOfReaders!=0 || NoOfWriters!=0)
, and not &&
.
class rw_lock_t {
int NoOfReaders;
int NoOfWriters, NoOfWritersWaiting;
pthread_mutex_t class_mutex;
pthread_cond_t reader_gate;
pthread_cond_t writer_gate;
public:
rw_lock_t()
: NoOfReaders(0), NoOfWriters(0), NoOfWritersWating(0),
class_mutex(PTHREAD_MUTEX_INITIALIZER),
reader_gate(PTHREAD_COND_INITIALIZER),
writer_gate(PTHREAD_COND_INITIALIZER)
{}
~rw_lock_t()
{
pthread_mutex_destroy(&class_mutex);
pthread_cond_destroy(&reader_gate);
pthread_cond_destroy(&writer_gate);
}
void r_lock()
{
pthread_mutex_lock(&class_mutex);
//while(NoOfWriters>0 || NoOfWritersWaiting>0) //Writer Preference
while(NoOfWriters>0)
{
pthread_cond_wait(&reader_gate, &class_mutex);
}
NoOfReaders++;
pthread_mutex_unlock(&class_mutex);
}
void w_lock()
{
pthread_mutex_lock(&class_mutex);
NoOfWritersWaiting++;
while(NoOfReaders>0 || NoOfWriters>0)
{
pthread_cond_wait(&writer_gate, &class_mutex);
}
NoOfWritersWaiting--; NoOfWriters++;
pthread_mutex_unlock(&class_mutex);
}
void r_unlock()
{
pthread_mutex_lock(&class_mutex);
NoOfReaders--;
if(NoOfReaders==0 && NoOfWritersWaiting>0)
pthread_cond_signal(&writer_gate);
pthread_mutex_unlock(&class_mutex);
}
void w_unlock()
{
pthread_mutex_lock(&class_mutex);
NoOfWriters--;
if(NoOfWritersWaiting>0)
pthread_cond_signal(&writer_gate);
//else //Writer Preference - don't signal readers unless no writers
pthread_cond_broadcast(&reader_gate);
pthread_mutex_unlock(&class_mutex);
}
};
class ReadWriteLock {
mutex writeLock;
mutex readLock;
int readCount;
public:
ReadWriteLock() {
readCount = 0;
}
void LockWrite() {
writeLock.lock();
}
void UnlockWrite() {
writeLock.unlock();
}
void LockRead() {
lock_guard<mutex> lock(readLock);
++readCount;
if (1 == readCount) {
LockWrite();
}
}
void UnlockRead() {
lock_guard<mutex> lock(readLock);
--readCount;
if (0 == readCount) {
UnlockWrite();
}
}
};
As Alexey pointed out, if the last read thread to UnlockWrite isn't the first read thread to LockWrite, the behavior is undefined. See std::mutex::unlock http://www.cplusplus.com/reference/mutex/mutex/unlock/ Windows ReleaseMutex: http://msdn.microsoft.com/en-us/library/windows/desktop/ms685066(v=vs.85).aspx