首页 > 解决方案 > 具有最大缓冲区大小问题的 1 个生产者 2 个消费者的最优控制

问题描述

我正在尝试编写一个多线程应用程序来将图像提供给我的机器学习模型。最初,每个生产者线程只有一个消费者线程(图像处理)(负责进行图像采集并将它们提供给缓冲区,如果有空闲空间)。现在我需要两个消费者来获取缓冲区中的所有图像。

对于单个生产者-消费者,我使用了一个互斥锁和两个信号量来确保缓冲区不会超过我建立的最大大小。代码是这样的:


sem_init(&waitPop, 0, bufferLimitSize) //wait pop is used to limit size of buffer
sem_init(&waitPush, 0, 0) //wait push is used to avoid trying to load from an empty buffer
    
void *producer(){
    while(thereAreImages){
        
        image = loadimage()
        sem_wait(&waitPop)
        mutex.lock()
        
//This part may be unnecesary or not well coded but adds more safety on limiting buffer size 
        if(buffer.size>=bufferLimitSize){
            mutex.unlock()
            mutex.lock()
        }

        buffer.push_front(image)
        mutex.unlock()
        sem_post(waitPush)
    }
}

void *consumer(){
    while(thereAreImages || !buffer.empty()){
        
        sem_wait(&waitPush)
        mutex.lock()

        data = buffer.back()
        image = data.clone()

        buffer.pop_back()

        mutex.unlock()

        sem_post(waitPop)

        doImageProcessing(image)
    }
}

这对我来说很好,我已经对其进行了很多测试,但现在我需要一个消费者线程来处理所有进入缓冲区的图像。基本上,我需要两个消费者处理相同的图像,即使他们的处理时间不同。几天来我一直想知道如何使用尽可能少的资源来管理它,但我还没有找到一种不会使缓冲区大小大于预期的方法。

总而言之,我需要两个消费者克隆进入缓冲区的每一个图像,同时避免向缓冲区提供比建立的缓冲区限制更多的图像,并在缓冲区为空时尝试访问。

提前致谢!

标签: multithreadingc++11

解决方案


我解决了我自己的问题,我会在这里写下来,以防你觉得它有用。只添加两个全局布尔变量并小心我以前使用的信号量对我来说很好用。生产者和以前一样,两个消费者都有相同的代码,只是布尔变量不同。此变量最初设置为 false,用于在其中一个线程已克隆最后一个缓冲区中的图像时进行注册。假设这些函数被称为 consumer1 和 consumer2 ,它们中的每一个都有一个布尔信号来指示图像已被克隆,signal1 和 signal2。

bool signal1 = false
bool signal2 = false

void *consumer1(){
    while(thereAreImages || !buffer.empty()){
        
        sem_wait(&waitPush)
        mutex.lock()

        if(signal1){
            printf("This image has already been processes")
            sem_post(waitPush)
            mutex.unlock()
            this_thread::sleep_for(std::chrono::milliseconds(10))//avoid using normal sleep() in multithreading!
            continue
        }
        data = buffer.back()
        image = data.clone()
        signal1 = true

        if(signal1 and signal2){
            buffer.pop_back()
            signal1 = signal2 = false
            sem_post(waitPop)
            mutex.unlock()
        }else{
            sem_post(waitPush)
            mutex.unlock()
        }

        doImageProcessing(image)
    }
    sem_post(waitPush) //To avoid semaphore deadlock when one thread finishes first
}

布尔变量总是在互斥锁期间被访问和写入,因此不应该有任何问题。希望你觉得它有用,如果你想到任何改进它的方法,请告诉我。


推荐阅读