/* ----------------------------------------------------------------- */ /* PROGRAM buffer.c */ /* This is a solution to the bounded buffer problem. Producers */ /* keep sending positive integers to a buffer and at the end EOD is */ /* sent indicating the end of data Consumers keep reading data */ /* from the buffer until they see EOD. EOD is defined to be a */ /* negative number. */ /* ----------------------------------------------------------------- */ #include #include #include #include #define MAX_SIZE 5 /* buffer size */ #define MAX_THREADS 5 /* # of producers/consumers */ #define EOD -1 /* end of data mark */ /* ----------------------------------------------------------------- */ /* Semaphores */ /* ----------------------------------------------------------------- */ sema_t UntilNotFull; /* if buffer is not full */ sema_t UntilNotEmpty; /* if buffer is not empty */ sema_t BufferLock; /* to lock the buffer */ sema_t ScreenLock; /* to lock the screen */ /* ----------------------------------------------------------------- */ /* The buffer */ /* ----------------------------------------------------------------- */ int Buffer[MAX_SIZE]; /* the buffer array */ int in, out; /* pointers in and out */ int Max_Run; /* max # of deposit/withdraw*/ /* ----------------------------------------------------------------- */ /* FUNCTION Fill() */ /* This function fills a char array with 'n' spaces. */ /* ----------------------------------------------------------------- */ void Fill(char x[], int n) { int i; for (i = 0; i < n*2; i++) x[i] = ' '; x[i] = '\0'; } /* ----------------------------------------------------------------- */ /* FUNCTION Producer() */ /* This is the producer thread. It sends out i*10000_j into the */ /* buffer, where i is the producer number and j is in the range of */ /* 0 and Max_Run-1. After this, it sends in EOD. */ /* ----------------------------------------------------------------- */ void *Producer(void *voidPTR) { int *intPTR = (int *) voidPTR; int ID = *intPTR; int i, data; char filler[100]; Fill(filler, ID); sema_wait(&ScreenLock); printf("%sProducer %d started ...\n", filler, ID); sema_post(&ScreenLock); for (i = 0; i < Max_Run; i++) { /* for each iteration */ thr_yield(); /* rest for unspecified time*/ sema_wait(&ScreenLock); /* lock the screen */ printf("%sProducer %d is waiting for an empty slot\n", filler, ID); /* display a message */ sema_post(&ScreenLock); /* release the screen */ data = ID*10000 + i; /* generate a data item */ sema_wait(&UntilNotFull); /* wait until buffer !full */ sema_wait(&BufferLock); /* lock the buffer */ Buffer[in] = data; /* deposit data */ in = (in + 1) % MAX_SIZE; /* advance in */ printf("%sProducer %d has added %d to the buffer\n", filler, ID, data); sema_post(&BufferLock); /* release buffer */ sema_post(&UntilNotEmpty); /* tells consumer data is in*/ } thr_yield(); /* rest for unspecified time*/ sema_wait(&UntilNotFull); /* done here. send EOD */ sema_wait(&BufferLock); /* it is the same as above */ Buffer[in] = EOD; in = (in + 1) % MAX_SIZE; printf("%sProducer %d adds EOD and exits\n", filler, ID); sema_post(&BufferLock); sema_post(&UntilNotEmpty); thr_exit(0); } /* ----------------------------------------------------------------- */ /* FUNCTION Consumer() */ /* This is the consumer thread. It keeps taking a data item from */ /* the buffer until the EOD mark is seen. */ /* ----------------------------------------------------------------- */ void *Consumer(void *voidPTR) { int *intPTR = (int *) voidPTR; int ID = *intPTR; int i, data; char filler[100]; Fill(filler, ID+10); sema_wait(&ScreenLock); printf("%sConsumer %d started ...\n", filler, ID); sema_post(&ScreenLock); do { /* iterate until EOD */ thr_yield(); /* rest for unspecified time*/ sema_wait(&ScreenLock); /* lock the screen */ printf("%sConsumer %d is waiting for an item\n", filler, ID); /* display a message */ sema_post(&ScreenLock); /* release the screen */ sema_wait(&UntilNotEmpty); /* wait until something in */ sema_wait(&BufferLock); /* lock the semaphore */ data = Buffer[out]; /* take the data item */ out = (out + 1) % MAX_SIZE; /* advance out */ if (data != EOD) /* if it is not EOD */ printf("%sConsumer %d has taken %d from the buffer\n", filler, ID, data); /* display data */ sema_post(&BufferLock); /* release the buffer */ sema_post(&UntilNotFull); /* tell producer slot avail */ } while (data != EOD); /* do until EOD is seen */ sema_wait(&ScreenLock); printf("%sConsumer %d receives EOD and exits\n", filler, ID); sema_post(&ScreenLock); thr_exit(0); } /* ----------------------------------------------------------------- */ /* The main program */ /* ----------------------------------------------------------------- */ void main(int argc, char *argv[]) { thread_t pID[MAX_THREADS]; /* producer ID */ thread_t cID[MAX_THREADS]; /* consumer ID */ size_t pStatus[MAX_THREADS]; /* producer status */ size_t cStatus[MAX_THREADS]; /* consumer status */ int pArg[MAX_THREADS]; /* producer argument */ int cArg[MAX_THREADS]; /* consumer argument */ int Threads; /* # of producers/consumers */ int i; if (argc != 3) { printf("Use %s #-of-iterations #-of-producers/consumers\n", argv[0]); exit(0); } Max_Run = abs(atoi(argv[1])); Threads = abs(atoi(argv[2])); if (Threads > MAX_THREADS) { printf("The no. of producers/consumers is too large. Reset to %d\n", MAX_THREADS); Threads = MAX_THREADS; } printf("Parent started ...\n"); /* initialize semaphores: */ /* ScreenLock - 1 (at most 1 thread can display) */ /* BufferLock - 1 (at most 1 thread can access buffer) */ /* UntilNotFull - 1 (at most MAX_SIZE threads can put data) */ /* UntilNotEmpty - 0 (no consumer can take data at beginning)*/ sema_init(&ScreenLock, 1, USYNC_THREAD, (void *) NULL); sema_init(&BufferLock, 1, USYNC_THREAD, (void *) NULL); sema_init(&UntilNotFull, MAX_SIZE, USYNC_THREAD, (void *) NULL); sema_init(&UntilNotEmpty, 0, USYNC_THREAD, (void *) NULL); in = out = 0; /* in and out start with 0 */ for (i = 0; i < Threads; i++) { /* start consumers first */ cArg[i] = i + 1; thr_create(NULL, 0, Consumer, (void *) &(cArg[i]), 0, (void *) &(cID[i])); } for (i = 0; i < Threads; i++) { /* followed by producers */ pArg[i] = i + 1; thr_create(NULL, 0, Producer, (void *) &(pArg[i]), 0, (void *) &(pID[i])); } for (i = 0; i < Threads; i++) /* wait producers/consumers */ thr_join(cID[i], 0, (void *) &(cStatus[i])); for (i = 0; i < Threads; i++) thr_join(pID[i], 0, (void *) &(pStatus[i])); printf("Parent exits ...\n"); }