多线程编程 - 生产者消费者

时间:2013-10-09 21:22:02

标签: multithreading

“实施不足”的伪代码' 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);
    }
}

1 个答案:

答案 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。虚假的唤醒的一个问题,但真正的问题是维基百科正在谈论的竞争条件。