Skip to content
UoL CS Notes

Producer-Consumer Problem

COMP124 Lectures

A producer process and a consumer process communicate via a buffer.

  • Producer Cycle:
    1. Produce item.
    2. Deposit in buffer.
  • Consumer Cycle:
    1. Extract item from buffer.
    2. 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.
  • It is non-deterministic and platform dependant.