这个生产者-消费者实现中是否存在竞争条件?
Are there race conditions in this producer-consumer implementation?
在操作系统概念(Silberschatz,第 9 版)的第 3.4.1 节中,作者提出了生产者-消费者问题并给出了以下使用循环缓冲区的实现(第 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
}
书上说:
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.
我没有看到生产者和消费者会同时访问相同 缓冲区元素的情况。
我的问题是:如果生产者和消费者运行在两个线程中,这个实现中是否存在竞争条件或其他同步问题?
有很多可能性
最明显的:如果有2个producer在生产数据。假设缓冲区中只有 1 个空闲 space,两个生产者线程都可以通过 while (in + 1) % BUFFER SIZE) == out
并尝试放入缓冲区。这可能会导致缓冲区损坏或数据丢失
即使只有1个消费者和1个生产者,仍然存在一些不太明显的问题。例如,编译器可能会重新排列行
buffer[in] = next_produced;
in = (in + 1) % BUFFER SIZE;
使 in
的更新早于 buffer
的更新发生,这会导致消费者访问未初始化的数据。
无法保证在修改 in
或 out
之前会看到对 buffer[x]
的写入
所以假设只有一个 reader 和一个编写器,那么 in、out 变量分别在一个线程中被修改。
buffer[in] = next_produced;
in = (in + 1) % BUFFER SIZE;
可以在reader中看到mis-ordered,导致reader在移动中看到,但是buffer[in]
的旧值
Item next_consumed = buffer[out];
out = (out + 1) % BUFFER SIZE;
可能被编译器或处理器排序错误,允许生产者在 next_consumed
读取值之前写入完整队列覆盖 buffer[out]
的值。
在操作系统概念(Silberschatz,第 9 版)的第 3.4.1 节中,作者提出了生产者-消费者问题并给出了以下使用循环缓冲区的实现(第 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
}
书上说:
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.
我没有看到生产者和消费者会同时访问相同 缓冲区元素的情况。
我的问题是:如果生产者和消费者运行在两个线程中,这个实现中是否存在竞争条件或其他同步问题?
有很多可能性
最明显的:如果有2个producer在生产数据。假设缓冲区中只有 1 个空闲 space,两个生产者线程都可以通过
while (in + 1) % BUFFER SIZE) == out
并尝试放入缓冲区。这可能会导致缓冲区损坏或数据丢失即使只有1个消费者和1个生产者,仍然存在一些不太明显的问题。例如,编译器可能会重新排列行
buffer[in] = next_produced; in = (in + 1) % BUFFER SIZE;
使
in
的更新早于buffer
的更新发生,这会导致消费者访问未初始化的数据。
无法保证在修改 in
或 out
buffer[x]
的写入
所以假设只有一个 reader 和一个编写器,那么 in、out 变量分别在一个线程中被修改。
buffer[in] = next_produced;
in = (in + 1) % BUFFER SIZE;
可以在reader中看到mis-ordered,导致reader在移动中看到,但是buffer[in]
的旧值Item next_consumed = buffer[out];
out = (out + 1) % BUFFER SIZE;
可能被编译器或处理器排序错误,允许生产者在 next_consumed
读取值之前写入完整队列覆盖 buffer[out]
的值。