Readers/Writers - CS 702 - Fall 2003
Tuesday, November 4, 2003
Loyola College >
Department of Computer Science >
CS 702 >
Examples and Lecture Notes >
Readers/Writers
Code for readers and writers (rw.cpp)
#include <cstdlib>
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include "object.h"
const int RW_DELAY_MAX = 4;
const int MAIN_DELAY_MAX = 2;
const int RECIP_P_WRITER = 3;
struct rw_args
{
int id;
Object *obj;
};
void *reader(void *p)
{
rw_args *args = static_cast(p);
std::cout << "Reader " << args->id << " preparing to read" << std::endl;
args->obj->beginRead();
std::cout << "Reader " << args->id << " reading" << std::endl;
int delay = random() % RW_DELAY_MAX;
sleep(delay);
std::cout << "Reader " << args->id << " finished reading" << std::endl;
args->obj->endRead();
delete args;
return NULL;
}
void *writer(void *p)
{
rw_args *args = static_cast(p);
std::cout << "Writer " << args->id << " preparing to write" << std::endl;
args->obj->beginWrite();
std::cout << "Writer " << args->id << " writing" << std::endl;
int delay = random() % RW_DELAY_MAX;
sleep(delay);
std::cout << "Writer " << args->id << " finished writing" << std::endl;
args->obj->endWrite();
delete args;
return NULL;
}
int main(int argc, char **argv)
{
int readers = 0;
int writers = 0;
Object *obj = new Object();
while (1)
{
int rnd = random() % RECIP_P_WRITER;
rw_args *args = new rw_args();
args->obj = obj;
pthread_t *thread = new pthread_t();
if (rnd == 0)
{
// make a writer
args->id = writers++;
pthread_create(thread, NULL, writer, args);
}
else
{
// make a reader
args->id = readers++;
pthread_create(thread, NULL, reader, args);
}
sleep(random() % MAIN_DELAY_MAX);
}
}
object.h
#ifndef __OBJECT_H__
#define __OBJECT_H__
class Object
{
public:
Object();
void beginRead();
void endRead();
void beginWrite();
void endWrite();
private:
int readersReading;
int readersWaiting;
int writersWaiting;
enum {IDLE, READING, WRITING};
int state;
static const pthread_mutex_t DEFAULT_MUTEX;
static const pthread_cond_t DEFAULT_COND;
pthread_mutex_t mutex;
pthread_cond_t read;
pthread_cond_t write;
};
#endif
object.cpp
#include <pthread.h>
#include "object.h"
const pthread_cond_t Object::DEFAULT_COND = PTHREAD_COND_INITIALIZER;
const pthread_mutex_t Object::DEFAULT_MUTEX = PTHREAD_MUTEX_INITIALIZER;
Object::Object()
: mutex(DEFAULT_MUTEX),
write(DEFAULT_COND),
read(DEFAULT_COND)
{
readersReading = 0;
readersWaiting = 0;
writersWaiting = 0;
state = IDLE;
}
void Object::beginRead()
{
pthread_mutex_lock(&mutex);
if (state == IDLE || (state == READING && writersWaiting == 0))
{
state = READING;
readersReading++;
}
else
{
readersWaiting++;
pthread_cond_wait(&read, &mutex);
}
pthread_mutex_unlock(&mutex);
}
void Object::endRead()
{
pthread_mutex_lock(&mutex);
readersReading--;
if (readersReading == 0 && writersWaiting > 0)
{
state = WRITING;
writersWaiting--;
pthread_cond_signal(&write);
}
else if (readersReading == 0)
state = IDLE;
pthread_mutex_unlock(&mutex);
}
void Object::beginWrite()
{
pthread_mutex_lock(&mutex);
if (state != IDLE)
{
writersWaiting++;
pthread_cond_wait(&write, &mutex);
}
else
state = WRITING;
pthread_mutex_unlock(&mutex);
}
void Object::endWrite()
{
pthread_mutex_lock(&mutex);
if (readersWaiting > 0)
{
readersReading = readersWaiting;
readersWaiting = 0;
state = READING;
pthread_cond_broadcast(&read);
}
else if (writersWaiting > 0)
{
writersWaiting--;
pthread_cond_signal(&write);
}
else
state = IDLE;
pthread_mutex_unlock(&mutex);
}
This code can also be downloaded from the following files:
object.h,
object.cpp, and
rw.cpp.