“实施不足”的伪代码' wikipedia中提到的生产者消费者问题如下。据说该解决方案具有可能导致死锁的竞争条件。
我的问题是:不会像以下那样修改唤醒其他线程的条件来解决可能的死锁问题。这样,不仅可以丢失一个唤醒,而是随后的多个唤醒,或者我错过了什么。试着在这里理解。
int itemCount = 0;
procedure producer() {
while (true) {
item = produceItem();
if (itemCount == BUFFER_SIZE) {
sleep();
}
putItemIntoBuffer(item);
itemCount = itemCount + 1;
//if (itemCount == 1) <<<<<<<< change this to below condition
if(itemCount > 0)
{
wakeup(consumer);
}
}
}
procedure consumer() {
while (true) {
if (itemCount == 0) {
sleep();
}
item = removeItemFromBuffer();
itemCount = itemCount - 1;
//if (itemCount == BUFFER_SIZE - 1) <<<<<<< Change this to below
if(itermCount < BUFFER_SIZE)
{
wakeup(producer);
}
consumeItem(item);
}
}
答案 0 :(得分:1)
不仅修改唤醒其他线程的条件如下解决了可能的死锁问题。
不,竞争条件仍然存在。问题是有多个线程正在进行消费和/或生产。当一个消费者(例如)被唤醒并被告知有待处理的项目时,它可能会删除该项目,但其他一些线程(或多个线程)已经在它之前到达。
解决方案是执行以下操作:
lock() {
while (itemCount == 0) {
sleep();
}
item = removeItemFromBuffer();
itemCount = itemCount - 1;
}
因此,即使消费者被唤醒,它也会立即检查 itemCount
不是0并且while
循环。即使itemCount
递增,另一个线程可能已删除该元素并在之前递减itemCount
,但获得该信号的线程有机会动作。那是比赛。
生产者方面也是如此,但竞争是阻止生产者过度填充缓冲区。生产者可能会被唤醒,因为有空间可用但是当它将项目放入缓冲区时,其他线程已经击败它并重新填充缓冲区。它必须再次测试,以确保它被唤醒后有空间。
我从我的网站Producer Consumer Thread Race Conditions开始,在此页面上逐行详细了解此种族。那里还有一个小测试程序来证明这个问题。
要实现的重点是,在大多数锁定实现中,有一个线程队列等待访问锁。当信号发送到线程时,它首先必须重新获取锁,之前它可以继续。当线程发出信号时,它会转到BLOCK队列的 end 。如果还有其他线程在等待锁定但不等待,则它们将在唤醒线程之前运行并窃取项目。
这与类似代码中关于while
循环的这个问题非常相似。不幸的是,接受的答案并没有解决这种竞争条件。请考虑提升my answer to a similar question here。虚假的唤醒是的一个问题,但真正的问题是维基百科正在谈论的竞争条件。