CS444 Handout: Semaphores, Producer-Consumer Problem (AKA bounded buffer)

Semaphores were invented in 1965 by Dijkstra. A semaphore is a system object with some sort of identifier, here “sem”.  The sem object has a count associated with it.  The two important operations on sem (after its creation) are (Tanenbaum, pg. 128, but underlined part here is not there but should be):

To make a real system, we also need to be able to create a semaphore with a certain initial count: sem = createsem(initcount).  POSIX semaphores: sem_init(…)

Tanenbaum, pg. 130: This program assumes semaphore creation somehow automatically happens, but in real life we need to do a system call to create a semaphore.  Here is that program rewritten to use POSIX semaphores.  It is still incomplete because of the thread creation calls, as well as the various unimplemented functions (produce_item, etc.).

02-28.jpg

Figure 2-28 pg. 130

 

 

 

Actual C program using POSIX semaphores, i.e., standard UNIX/Linux semaphores

 

/* needs various headers, including <semaphore.h> */

sem_t mutex, empty, full;  /* struct type sem_t is defined in header */

int main()

{

       if (sem_init(&mutex, /*process-local*/ 0, /*init count*/ 1) < 0) 

         perror("Failed to create semaphore 1");   

          return 1;

        }

       if (sem_init(&empty, /*process-local*/ 0, /*init count*/ N) < 0)

         perror("Failed to create semaphore 2");

          return 1;

        }

       if (sem_init(&full, /*process-local*/ 0, /*init count*/ 0) < 0)

         perror("Failed to create semaphore 3");

          return 1;

        }

       thread_create(producer, ...);    

thread_create(consumer, ...); 

       getchar();              /* block main thread */

       /* here, could bring down threads and destroy semaphores, but exit will do it for us */

       return 0;

}
 

/* producer() and consumer() are close to Tanenbaum, pg. 130 */

/* Note: each system call should have its return value tested as show above for   sem_init */

void producer()

{

       int item;

 

       while (TRUE) {

          item = produce_item();

          sem_wait(&empty);        /* down: block for/claim empty spot for new item */

          sem_wait(&mutex);

          insert_item(item);       /* insert item, protected by mutex */

          sem_post(&mutex);

          sem_post(&full);         /* up: signal filled-in spot */

       }

}

 

void consumer()

{

       int item;

 

       while (TRUE) {

          sem_wait(&full);         /* down: block for/claim filled spot in buffer */

          sem_wait(&mutex);

          item = remove_item();    /* remove item, protected by mutex */

          sem_post(&mutex);

          sem_post(&empty);        /* up: signal empty spot */

          consume_item(item);

       }

}