问题
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?
回答1:
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 dataEven 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 ofbuffer
, which cause the consumer accessing uninitialized data.
回答2:
There is no guarantee that a write to buffer[x]
would be seen before a modification of in
or out
So assuming only one reader and one writer, then the in, out variables are each modified in a single thread.
buffer[in] = next_produced;
in = (in + 1) % BUFFER SIZE;
Could be seen mis-ordered in the reader, causing the reader to see in moved, but the old value of buffer[in]
Item next_consumed = buffer[out];
out = (out + 1) % BUFFER SIZE;
Could be misordered by the compiler, or the processor, allowing the producer to write into the full queue overwriting the value of buffer[out]
before the next_consumed
has read the value.
来源:https://stackoverflow.com/questions/34805289/are-there-race-conditions-in-this-producer-consumer-implementation