Definition
+----------+ +----------+
| | +----------+ | |
| Producer |--->| Buffer |--->| Consumer |
| | +----------+ | |
+----------+ +----------+
- The producer puts objects into a shared buffer.
- The consumer takes them out.
- There must be a synchronisation to coordinate between the producer and the consumer.
- The producer and the consumer should not need to work in lock step; there is a fixed-size buffer between them.
- The access to this buffer must be synchronised.
- The producer must wait if the buffer is full.
- The consumer must wait if the buffer is empty.
Implementation Example
- Producer
for (int i = 0; i<MAX_LOOP; i++)
{
try_put (i);
}- Consumer
while (true)
{
int tmp = try_get ();
printf ("%d\n", tmp);
}Initially, the buffer is a queue with front = tail = 0, and the lock is initially free. Let MAX be the maximum capacity of the buffer. Then, the try_put () and try_get () can be implemented as follows.
try_put
try_put (item)
{
lock.acquire ();
if ((tail - front) < size) // Buffer is not full
{
buffer[tail % MAX] = item;
tail++;
}
lock.release ();
}try_get
try_get ()
{
item = NULL;
lock_acquire ();
if (front < tail) // Buffer is not empty
{
item = buffer[front % MAX];
front++;
}
lock_release ();
return item;
}Here, the shared states are buffer, front, and tail.
However, one cannot assure that the buffer is empty when try_get () returns NULL.
- If a producer generates an item between
lock_release ()andreturn, even though thebufferis not empty,try_get ()returnsNULL. - For a thread to know when the
bufferis empty, there must be another primitive for the purpose.