生产者消费者仅使用1个额外的信号量

时间:2018-09-04 01:55:13

标签: multithreading operating-system mutex semaphore

Solution traditional to producer-consumer

在操作系统中,如您在上面的生产者消费者链接中所看到的,使用了两个信号量fullempty,为什么不可能仅使用一个数量的信号量fullEmpty

我的意思是,我们有一个二进制信号量mutex和另一个信号量fullEmpty,最初是0,因为缓冲区中没有项目,所以为什么需要 2个信号灯(fullempty)?

唯一的事情是waitsignal的顺序需要更改,以便fullEmpty的更新在关键部分内。

有什么想法或理由吗?

2 个答案:

答案 0 :(得分:1)

说明中与您的答案相关的主要说明是“我们有固定大小的缓冲区。”

为了回答您的问题,我们首先假定缓冲区可以扩展以容纳所需的所有项目,换句话说,缓冲区可以增长到无限大小。在这种情况下,生产者和使用者之间唯一需要进行的同步(除了锁定互斥锁以确保您不会破坏关键部分中的项目),还要确保使用者仅在之后食用

制作人

do {
    //produce an item

    wait(mutex);

    //place in buffer

    signal(mutex);
    signal(full);

} while (true);

消费者

do {
    wait(full);
    wait(mutex);

    //remove item from buffer

    signal(mutex);

    //consume item

} while (true);

正如您在上面看到的,生产者总是能够将事物添加到队列中(除了持有互斥锁的时间),并且不需要等待使用者消耗任何东西,因为缓冲区永远不会填满,甚至如果消费者不消费物品。另一方面,在生产者生产商品之前,消费者无法消费任何东西。


要回答您的问题,您需要关注以下语句:“我们有固定大小的缓冲区”。这改变了问题。由于缓冲区不再能够增长到无限大小,因此您需要让生产者在缓冲区已满时等待,然后他们才能向缓冲区添加更多内容。这就是为什么您需要第二个信号灯的原因。消费者不仅需要等待生产者,而且现在生产者也需要等待消费者。通过让生产者在仅消费者调用wait的信号量上调用signal,可以使生产者等待消费者。

您不能仅使用一个信号量来执行此操作,因为生产者必须等待的条件与消费者必须等待的条件不同。由于它们应该能够在不同的条件下递减并越过信号量,因此您不能对两者使用相同的信号量。

答案 1 :(得分:0)

这是因为必须等待两个条件:队列为空,队列已满。但是经典信号量只允许您等待一种情况-等待信号量不为0。

可以使用单个同步对象解决此问题,但是该对象需要比信号量更完整的功能。 “有界信号量”-具有最大值的信号量就足够了,因为它可以让您阻止等待两种情况。

如何获得另一个问题:

我建议您熟悉UMTX_OP_WAKE接口-与常规接口相比,它可以构建更强大,更高效的同步对象。今天,大多数操作系统都提供了等效的接口,甚至C ++将来都可能引入类似的内容(请参见std::synchronic<T>)。


一些注意事项:

Linux具有eventfd,当使用futex标志创建时,Linux可以充当信号灯,但是它的最大值为EFD_SEMAPHORE,并且不能更改。也许有一天这个系统调用也将扩展为支持最大值。