【问题标题】:Producer Consumer synchronization with only 1 semaphore仅使用 1 个信号量的生产者消费者同步
【发布时间】:2019-08-14 14:14:43
【问题描述】:

在Producer-Consumer problem 中,标准解决方案使用 3 个信号量。
但是,我想知道我们是否可以只使用 1 个信号量:

semaphore mutex = 1

procedure producer() {
    while (true) {
        down(mutex)
        if (bufferNotFull()) {
            item = produceItem()
            putItemIntoBuffer(item)
        }
        up(mutex)
    }
}

procedure consumer() {
    while (true) {
        down(mutex)
        if (bufferNotEmpty()) {
            item = removeItemFromBuffer()
            consumeItem(item)
        }
        up(mutex)
    }
}

这个解决方案和标准解决方案一样好吗??

参考标准溶液:

semaphore mutex = 1
semaphore fillCount = 0
semaphore emptyCount = BUFFER_SIZE

procedure producer() {
    while (true) {
        item = produceItem()
        down(emptyCount)
        down(mutex)
        putItemIntoBuffer(item)
        up(mutex)
        up(fillCount)
    }
}

procedure consumer() {
    while (true) {
        down(fillCount)
        down(mutex)
        item = removeItemFromBuffer()
        consumeItem(item)
        up(mutex)
        up(emptyCount)
    }
}

【问题讨论】:

    标签: multithreading synchronization semaphore producer-consumer


    【解决方案1】:

    “标准解决方案”不必使用 3 个信号量。即使是您链接的维基百科文章也有一个双信号量解决方案,适用于有一个生产者和一个消费者的情况:

    semaphore fillCount = 0; // items produced
    semaphore emptyCount = BUFFER_SIZE; // remaining space
    
    procedure producer() 
    {
        while (true) 
        {
            item = produceItem();
            down(emptyCount);
            putItemIntoBuffer(item);
            up(fillCount);
        }
    }
    
    procedure consumer() 
    {
        while (true) 
        {
            down(fillCount);
            item = removeItemFromBuffer();
            up(emptyCount);
            consumeItem(item);
        }
    }
    

    具有单个信号量的解决方案并不是很好,因为当您真正想要时,它们只给您一个等待条件 - “等待可用空间”和“等待一个项目”。你不能同时使用一个信号量。

    无论如何,您的解决方案没有错,只是效率非常低,因为在任何给定时刻,只有一个生产者或单个消费者可以运行。这本质上是单线程代码,只有线程之间的锁和上下文切换。所以它比实际的单线程代码效率更低。

    还有一件事 - 物品生产和消费通常不是关键部分的一部分。在消费或生产项目时,另一个线程可以运行。只有在使用缓冲区时才需要互斥。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多