这个生产者 - 消费者实施中是否存在竞争条件?

时间:2016-01-15 06:12:00

标签: c multithreading producer-consumer

在操作系统概念的第3.4.1节(Silberschatz,第9版)中,作者介绍了生产者 - 消费者问题,并给出了以下使用循环缓冲区的实现(第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
}

这本书说:

  

这个例子中的一个问题并没有解决有关情况的问题   生产者流程和消费者流程都试图这样做   同时访问共享缓冲区。

我没有看到生产者和消费者同时访问相同缓冲元素的情况。

我的问题是:如果生产者和消费者在两个线程中运行,那么这个实现中是否存在竞争条件或其他同步问题?

2 个答案:

答案 0 :(得分:2)

有很多可能性

  1. 最明显的:如果有2个生产者生成数据。假设缓冲区中只有1个可用空间,则两个生成器线程都可以通过while (in + 1) % BUFFER SIZE) == out并尝试放入缓冲区。这可能导致缓冲区损坏或数据丢失

  2. 即使只有1个消费者和1个生产者,仍然存在一些不太明显的问题。例如,编译器可能会重新排列行

    buffer[in] = next_produced;
    in = (in + 1) % BUFFER SIZE;
    

    使in的更新发生在更新buffer之前,这会导致消费者访问未初始化的数据。

答案 1 :(得分:2)

无法保证在修改buffer[x]in

之前会看到对out的写入

因此假设只有一个读者和一个编写者,那么in,out变量都在一个线程中被修改。

buffer[in] = next_produced;
in = (in + 1) % BUFFER SIZE;

可以看到读者错误排序,导致读者看到移动,但缓冲区的旧值[in]

Item next_consumed = buffer[out];
out = (out + 1) % BUFFER SIZE;

编译器或处理器可能会造成错误,允许生产者在buffer[out]读取值之前写入完整队列覆盖next_consumed的值。