/* Readers/Writers Problem - Solution 3 For more details, see Andrew S. Tanenbaum and Albert S. Woodhull, Operating Systems: Design and Implementation, 2nd Edition, Prentice-Hall, pp. 77-80 Copyright (c) 2001 Xiao Zhang */ #include #include #include #include /**********************************************************************/ /* Solution 3: When a reader arrives and a writer is waiting, the */ /* reader is suspended behind the writer instead of being admitted */ /* immediately. In this way, a writer has to wait for readers that */ /* were active when it arrived to finish but does not to wait for */ /* readers that came along after it. */ /**********************************************************************/ class ReadWriteMutex { private: int rc; /* readcount */ pthread_mutex_t rc_mutex; pthread_mutex_t r_mutex; pthread_mutex_t w_mutex; public: ReadWriteMutex() { rc = 0; pthread_mutex_init(&rc_mutex, NULL); pthread_mutex_init(&r_mutex, NULL); pthread_mutex_init(&w_mutex, NULL); } void read_lock() { pthread_mutex_lock(&r_mutex); pthread_mutex_lock(&rc_mutex); rc++; if (rc == 1) pthread_mutex_lock(&w_mutex); pthread_mutex_unlock(&rc_mutex); pthread_mutex_unlock(&r_mutex); } void read_unlock() { pthread_mutex_lock(&rc_mutex); rc--; if (rc == 0) pthread_mutex_unlock(&w_mutex); pthread_mutex_unlock(&rc_mutex); } void write_lock() { pthread_mutex_lock(&r_mutex); pthread_mutex_lock(&w_mutex); } void write_unlock() { pthread_mutex_unlock(&w_mutex); pthread_mutex_unlock(&r_mutex); } }; /**********************************************************************/ /* Below is the program for testing the above protocol. */ /* We create several readers which read `current_time' and writers */ /* which set `current_time'. */ /**********************************************************************/ #define READERS 4 #define WRITERS 4 ReadWriteMutex rw_mutex; int current_time; int ready = 0; pthread_mutex_t ready_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t ready_cond = PTHREAD_COND_INITIALIZER; int go = 0; pthread_mutex_t go_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t go_cond = PTHREAD_COND_INITIALIZER; pthread_mutex_t screen = PTHREAD_MUTEX_INITIALIZER; void ready_to_go() { pthread_mutex_lock(&ready_mutex); ready++; pthread_mutex_unlock(&ready_mutex); pthread_cond_signal(&ready_cond); pthread_mutex_lock(&go_mutex); while (go == 0) pthread_cond_wait(&go_cond, &go_mutex); pthread_mutex_unlock(&go_mutex); } void *reader(void *arg) { ready_to_go(); int i,j; for (i = 0; i < 100; i++) { int local_time; rw_mutex.read_lock(); for (j = 0; j < 1000000; j++) local_time = current_time; /* screen lock is necessary for readers because multiple readers can print simultanously. */ pthread_mutex_lock(&screen); cout << pthread_self() << ":" << i << ": read current_time = " << local_time << endl; pthread_mutex_unlock(&screen); rw_mutex.read_unlock(); } return NULL; } void *writer(void *arg) { ready_to_go(); int i,j; for (i = 0; i < 100; i++) { rw_mutex.write_lock(); for (j = 0; j < 100000; j++) current_time = time(0); cout << pthread_self() << ":" << i << ": write current_time = " << current_time << endl; rw_mutex.write_unlock(); } return NULL; } int main() { int i; pthread_t rid[READERS], wid[WRITERS]; for (i = 0; i < READERS; i++) pthread_create(&rid[i], NULL, reader, NULL); for (i = 0; i < WRITERS; i++) pthread_create(&wid[i], NULL, writer, NULL); pthread_mutex_lock(&ready_mutex); while (ready != READERS + WRITERS) pthread_cond_wait(&ready_cond, &ready_mutex); pthread_mutex_unlock(&ready_mutex); go = 1; pthread_cond_broadcast(&go_cond); for (i = 0; i < READERS; i++) pthread_join(rid[i], NULL); for (i = 0; i < WRITERS; i++) pthread_join(wid[i], NULL); return 0; }