Search code examples
coperating-systemsemaphoreproducer-consumer

Is there a way to do the producer-consumer problem with 2 semaphores?


This is the solution using 3 semaphores. Wondering if there's a way to do with fewer and if not, why not?

   sem_t full; // # of filled slots
   sem_t empty; // # of empty slots
   sem_t mutex; // mutual exclusion

   sem_init(&full, 0, 0);
   sem_init(&empty, 0, N);
   sem_init(&mutex, 0, 1);

   Producer(){
      sem_down(empty);
      sem_down(&mutex);
      // fill a slot
      sem_up(&mutex);
      sem_up(full);
   }

   Consumer() {
      sem_down(full);
      sem_down(&mutex);
      // empty a slot
      sem_up(&mutex);
      sem_up(empty);
   }

Solution

  • The only way to avoid the the mutex is if all operations inside the semaphore are atomic (can be rare). The mutex is there to make sure the dangerous bits happen one at a time and without being interrupted.

    Imagine if you had two threads attempting to do something that depended on each other.

    Thread 1:  Add 3 to the ordered list
    Thread 2:  Add 4 to the ordered list
    List:  { 1, 2, 5, 7}
    

    Thread 2 needs to see where thread 1 sticks his number before inserting his own. Therefore we use a mutex to make sure only one thread at a time tries to insert their number into the list.

    The way it is written in your example (and others online) might make one believe the whole process needs to be inside the mutex. If you did this only one thread would be able to work at a time! In actuality you would do stuff that doesn't depend on other threads outside of the mutex but inside the semaphore (say generating a random number) and only guard the insertion of the number into the list.

    semaphore(x)
    long_expensive_computation
    mutex(y)
    order_critical_stuff
    release(y)
    release(x)