CS444 Handout: Semaphores, Monitors

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. 110):

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. 112: 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.).

/* 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 */

}
 

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

/* 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);        /* claim empty spot */

          sem_wait(&mutex);

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

          sem_post(&mutex);

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

       }

}

 

void consumer()

{

       int item;

 

       while (TRUE) {

          sem_wait(&full);         /* claim spot in buffer */

          sem_wait(&mutex);

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

          sem_post(&mutex);

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

          consume_item(item);

       }

}

 

Monitors: Packages of code with their own special mutex ensuring that only one thread at a time can execute inside it. Other threads wait for their turn.  Not available in C or C++.

Example of Monitor in Java.  In Java, we have the “synchronized” keyword to cause an object to have a mutex that ensures that only one thread at a time can execute in any of its synchronized methods.  Thus its fields can be protected from simultaneous access by multiple threads.

public class OurMonitor0 {  // this is a monitor

      private int buffer[] = new int[N];  // queue in ring buffer

      private int count = 0, lo = 0, hi = 0;

 

      public sychronized boolean insert(int val) {

            if (count == N) return false;  // fail if full

            buffer[hi] = val;      // enqueue val, step 1

            hi = (hi + 1) % N;     // enqueue, step 2

            count++;              // enqueue, step 3

            return true;

      }

      // return positive number, or -1 if nothing is there

      public synchronized int remove() {

            int val;

            if (count == 0) return –1; 

            val = buffer[lo];     // dequeue val, step 1

            lo = (lo + 1) % N;    // dequeue, step 2

     count--;              // dequeue, step 3

            return val;

      }

}

 

 

Note: if your methods are static and synchronized, you get a mutex in the class instance to protect them. Note this is a different mutex from any object mutex, so static and non-static synchronized methods are not coordinated.

Full-featured monitors also provide appropriate blocking capability, more on this next time.