begin_reading() and begin_writing() both enter the monitor and then check to see if they should sleep. If they do, they increment the proper sleeping variable, and wait on the proper condition variable. This is done in a while loop that will not be exited unless the proper conditions hold for reading/writing.
When the while loop is exited, nreaders or nwriters is incremented, the monitor is released, and the procedures exit. Additionally, begin_reading() calls cv_notify() on the reading condition variable just before it exits if there are any more sleeping readers. This is because multiple readers may access the data at once.
end_reading() decrements nreaders and if it is the last reader, it wakes up any writing threads that are sleeping. end_writing decrements nwriters and wakes up readers or writers if there are any sleeping. Notice it does this in preference to readers. It also only wakes up one reader. It assumes that that reader will wake up the rest in begin_reading().
mon_t mon; cv_t read_cv; cv_t write_cv; int sleeping_readers; int sleeping_writers; int nreaders; int nwriters; initialize() { mon = mon_create(); read_cv = cv_create(mon); write_cv = cv_create(mon); sleeping_readers = 0; sleeping_writers = 0; nreaders = 0; nwriters = 0; } begin_reading() { mon_enter(mon); while(nwriters > 0) { sleeping_readers++; cv_wait(read_cv); sleeping_readers-- } nreaders++; if (sleeping_readers > 0) cv_notify(read_cv); mon_exit(mon); } end_reading() { mon_enter(mon); nreaders--; if (nreaders == 0) { cv_notify(write_cv); } mon_exit(mon); } begin_writing() { mon_enter(mon); while (nreaders > 0 || nwriters > 0) { sleeping_writers++; cv_wait(write_cv); sleeping_writers-- } nwriters++; mon_exit(mon); } end_writing() { mon_enter(mon); if (sleeping_readers > 0) { cv_notify(read_cv); } else if (sleeping_writers > 0) { cv_notify(write_cv); } mon_exit(mon); }
static int rw = 0; end_writing() { mon_enter(mon); if (sleeping_readers > 0 && sleeping_writers > 0 && rw) { cv_notify(read_cv); rw = !rw; } else if (sleeping_readers > 0 && sleeping_writers> 0 ) { cv_notify(write_cv); rw = !rw; } else if (sleeping_readers > 0) { cv_notify(read_cv); } else if (sleeping_writers > 0) { cv_notify(write_cv); } mon_exit(mon); }