In section 3.4.1 of Operating System Concepts (Silberschatz, 9th edition), the authors present the producer-consumer problem and give the following implementation that uses a circular buffer (page 125, 126).
//Shared variables
#define BUFFER SIZE 10
struct Item;
Item buffer[BUFFER SIZE];
int in = 0, out = 0;
//buffer is empty when in == out
//buffer is full when (in + 1) % BUFFER SIZE == out
//Producer
while (true)
{
Item next_produced = /*produce item here*/;
while (((in + 1) % BUFFER SIZE) == out) ; //do nothing
buffer[in] = next_produced;
in = (in + 1) % BUFFER SIZE;
}
//Consumer
while (true)
{
while (in == out) ; //do nothing
Item next_consumed = buffer[out];
out = (out + 1) % BUFFER SIZE;
//consume the item in next_consumed here
}
The book says:
One issue this illustration does not address concerns the situation in which both the producer process and the consumer process attempt to access the shared buffer concurrently.
I do not see a situation where the producer and consumer would access the same buffer element simultaneously.
My question is: if the producer and consumer ran in two threads, are there race conditions or other synchronization problems in this implementation?
There is a lot of possibilities
The most obvious: if there are 2 producer producing data. Assuming there is only 1 free space in the buffer, both producer thread can get pass the while (in + 1) % BUFFER SIZE) == out and try to put to the buffer. This can lead to corrupted buffer or missing data
Even there is only 1 consumer and 1 producer, there are still some less obvious problem. For example, compiler may rearrange the lines
buffer[in] = next_produced;
in = (in + 1) % BUFFER SIZE;
to make the update of in happen earlier than update of buffer, which cause the consumer accessing uninitialized data.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With