Search code examples
cmultithreadingproducer-consumer

Are there race conditions in this producer-consumer implementation?


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?


Solution

  • There is a lot of possibilities

    1. 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

    2. 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.