Synchronization Producer/Consumer Problem Abstract The producer/consumer problem is a classical synchronization exercise. The problem defines an arbitrary number of so-called producers which create goods and consumers which consume these goods. A bounded buffer of size n mediates among producers and consumers and adapts to the different execution speeds of all the involved processes resp. threads. Besides mutual exclusion issues, semaphores are required to block consumers until consumable goods are inside the buffer and to block producers until there is free space available inside the buffer to deposit additional goods. It is noteworthy that for these additional semaphores, the semaphore functions are called by opposite processes or threads (asymmetrical solution). Synchronization - PC with Semaphores 2 Producers Motivation Buffer • n threads produce some good Consumers • m threads consume some good • Bounded buffer between producers and consumers – adapt to varying execution speeds – minimize waiting time • How to synchronize the n+m threads? Synchronization - PC with Semaphores 3 Example Buffer with 1 slot Consumer Producer Synchronization - PC with Semaphores 4 Outline of Buffer public class Buffer { public Buffer ( int n ) { } /// Inserts another good into the buffer. /// May block until free space is available. public void Produce ( int good ) { } /// Consumes a good stored inside the buffer. /// May signal blocked producer threads. public int Consume () { return 42; } } Synchronization - PC with Semaphores 5 Producer (C#) public class Producer { public Producer ( Buffer b ) { buffer = b; my_id = this.GetHashCode(); ThreadStart ts = new ThreadStart(Run); my_thread = new Thread(ts); my_thread.Start(); } private void Run () { Console.WriteLine("Producer {0}: started ...",my_id); int good = this.GetHashCode() * 1000000; while (true) { buffer.Produce(good); Console.WriteLine("Producer {0}: good {1} stored",my_id,good); good++; } } private Buffer buffer; private Thread my_thread; private int my_id; } Synchronization - PC with Semaphores 6 Consumer (C#) public class Consumer { public Consumer ( Buffer b ) { buffer = b; my_id = this.GetHashCode(); ThreadStart ts = new ThreadStart(Run); my_thread = new Thread(ts); my_thread.Start(); } private void Run () { Console.WriteLine("Consumer {0}: started ...",my_id); while (true) { int good = buffer.Consume(); Console.WriteLine("Consumer {0}: good {1} retrieved",my_id,good); } } private Buffer buffer; private Thread my_thread; private int my_id; } Synchronization - PC with Semaphores 7 Exercise • Implement the buffer – Producers must block if buffer is full – Consumers must block if buffer is empty – Access to shared data structures should be mutally exclusive • Examine the running solution Synchronization - PC with Semaphores 8 The Buffer (C#) public class Buffer { public Buffer ( int n ) { this.n = n; slots = new int[n]; mutex = new Semaphore(1); slots_available = new Semaphore(n); goods_available = new Semaphore(0); } … private private private private private private private int n; int [] slots; int free = 0; int used = 0; Semaphore mutex; Semaphore slots_available; Semaphore goods_available; public void Produce ( int good ) { slots_available.P(); mutex.P(); slots[free] = good; free = (free+1) % n; mutex.V(); goods_available.V(); } public int Consume () { goods_available.P(); mutex.P(); int good = slots[used]; used = (used+1) % n; mutex.V(); slots_available.V(); return good; } } Synchronization - PC with Semaphores 9 Program Behavior Program Visualization Consumer Producers Program State Synchronization - PC with Semaphores 10 Resources • Every textbook on operating systems has a section on solving the producer/consumer problem with semaphores • The "Little Book on Semaphores" by Allen B. Downey Synchronization - PC with Semaphores 11