20.7 The readers writers problem with write preference


#1

I’m having trouble understanding why the solution to this problem may starve readers. If you have reader and writer threads waiting for a write lock, the writer threads have no advantage. Either type could be the next one to grab the write lock and execute.


#2

I also agree that it cannot specifically starve a reader. But it has another problem; when writer 1 is writing and writer 2 arrives and then reader 3 arrives, this algorithm cannot guarantee that writer 2 will write before reader 2 reads. This essentially means that any task can starve irrespective of whether it is reader or writer.

A solution will be getting the incoming task in a queue and do the operation in FIFO order. I have the following code working for me:

void Dispatcher(queue<RWEnum>& q)
{
	while(true) {
		RWEnum task;
		bool got = false;
		{
			unique_lock<mutex> u_lock(RW::q_mutex);
			if(!q.empty()) {
				task = q.front();
				got = true;
			}
		}

		if (got) {
			if(task == RWEnum::READ) {
				{
					unique_lock<mutex> u_lock(RW::rw_mutex);
					if(!RW::writing) {
						++RW::reader_count;
						thread(Reader).detach();
						{
							lock_guard<mutex> lg(RW::q_mutex);
							q.pop();	
						}
					} else {
						while(RW::writing) {
							RW::convar_rw.wait(u_lock);
						}
					}
				}
			}
			else if(task == RWEnum::WRITE) {
				{
					unique_lock<mutex> u_lock(RW::rw_mutex);
					if(!RW::writing && RW::reader_count == 0) {
						RW::writing = true;
						thread(Writer).detach();
						{
							lock_guard<mutex> lg(RW::q_mutex);
							q.pop();	
						}
					} else {
						while(RW::writing || RW::reader_count != 0) {
							RW::convar_rw.wait(u_lock);
						}
					}
				}
			}
		}

		{
			unique_lock<mutex> q_lock(RW::q_mutex);
			if(q.empty()) {
				RW::convar_empty_queue.wait(q_lock);
			}
		}
	}
}