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 thebuffer
is not empty,try_get ()
returnsNULL
. - For a thread to know when the
buffer
is empty, there must be another primitive for the purpose.