Producer-Consumer Problem
A producer process and a consumer process communicate via a buffer.
- Producer Cycle:
- Produce item.
- Deposit in buffer.
- Consumer Cycle:
- Extract item from buffer.
- Process the item.
There can be many producers and consumers, sometimes in a chain.
Issues
We have to ensure that:
- Producer cannot put items in a full buffer.
- Consumer cannot extract items from buffer if it is empty.
- Buffer is not accessed by two thread simultaneously.
Implementation
Main Thread
public class Prodcon
{
public static void main (String args[])
{ // Create buffer, producer & consumer
Buffer b = new Buffer();
Producer p = new Producer(b);
Consumer c = new Consumer(b);
p.start(); c.start();
...
}
}
Producer and Consumer Classes
class Producer extends Thread {
private Buffer b;
public Producer (Buffer buf) {
b = buf;
}
public void run() {
int m;
...
b.insert(m);
...
}
}
Consumer is similar, but calls n = b.remove()
Buffer Class With Semaphore
class Buffer {
private int v;
private volatile boolean empty=true;
public void insert (int x) {
while (!empty)
; // null loop
empty = false;
v = x;
}
public int remove() {
while (empty)
; // null loop
empty = true;
return (v);
}
}
- The
empty
boolean tells us if the buffer is empty or not.-
volatile
ensures the computer will re-load the variable each time it is tested, rather than transferring it to a register.This says that the value could change without the compiler being aware.
-
- A producer will wait while the buffer is full. A consumer will wait while it is empty.
- Busy waiting (spinlock)
- This simulates the
wait
operation.
- Busy waiting is inefficient
- A thread or process does nothing useful while it has the CPU.
- Spinlocks are useful only in a multiprocessor situation when expected wait time is very short.
Yielding
It may be more efficient for a waiting thread or process to relinquish control of the CPU:
public void insert (int x) {
while(!empty)
Thread.yield();
empty = false;
v = x;
}
The yield()
call tells the JVM that the thread is willing to give up the CPU.
- The JVM might ignore it depending on the implementation.
- This is why it is in a
while
loop so that!empty
is tested many times.
- This is why it is in a
- It is non-deterministic and platform dependant.