简体   繁体   English

优化生产者之间的交互-使用者线程

[英]Optimizing interaction between Producer - Consumer threads

I have an implementation of Producer-Consumer multi-threaded interaction.It works.But I feel that during the execution wait states happen too often between Consumer thread and Producer.In my case Consumer accesses a queue at random intervals and takes data from it.Now,the producer thread runs during the whole process life time.The producer thread works as caching machine.It checks in a loop if the size of queue is smaller than the maximum cache size allowed and if that's the case it keeps pushing new data into that cache.My concern is that when the consumer tries to access the queue the last is still locked by the producer thread and the consumer should wait.Ideally,I would like to have the consumer causing the producer 'freeze' and unlock immediately while the consumer retrieves data from the queue. 我有一个Producer-Consumer多线程交互的实现,它起作用了,但是我感觉执行期间在Consumer线程和Producer之间的等待状态经常发生,在我的情况下,Consumer随机访问一个队列并从中获取数据。现在,生产者线程在整个过程生命周期中运行。生产者线程充当缓存机。它在循环中检查队列大小是否小于允许的最大缓存大小,如果是这种情况,它将继续将新数据推入我担心的是,当使用者尝试访问队列时,最后一个仍被生产者线程锁定,使用者应等待。理想情况下,我希望使用者使生产者“冻结”并立即解锁。使用者从队列中检索数据。

Here is how I am doing it now: 这是我现在的做法:

   //Called by consumer(main thead) to retrieve data from cache
   uint8_t* Worker::GetFrame() {

      boost::unique_lock<boost::mutex> lk(_frameCacheMutex);
      //If the cache is empty:
      while (0 == _frames_cache.size()) {
               //tell Producer to push data into cache
             _fill_cache_wait_cond.notify_one();
              //wait for the data to arrive(will be signaled by worker thread)
             _get_frame_wait_cond.wait(lk);

      }
      uint8_t * fr = _frames_cache.front();
      _frames_cache.pop();
      // notify worker thread to continue caching
      _fill_cache_wait_cond.notify_one();

      return fr;
   }

Producer thread: 生产者线程:

    void Worker::operator () () {
      //Some init here..
        while (isRunning) {
           boost::unique_lock<boost::mutex> lk(_frameCacheMutex);

           /// Here create the data for cache...

           _frames_cache.push(data);

           /// Notify waiting main thread to take data
           _get_frame_wait_cond.notify_one();

           /// If the cache is full ,wait
           while (_frames_cache.size() == cacheMaxSize ){

                 _fill_cache_wait_cond.wait(lk);

           }

        }     

    }

At this moment, the producer locks the queue until it is full. 此时,生产者将队列锁定,直到队列满为止。 Only at that time, the consumer can access the queue, but it signals immediately that the queue is not full anymore, so the producer locks the queue again. 仅在那时,使用者可以访问该队列,但是会立即发出信号,通知该队列不再满,因此生产者再次锁定该队列。

At least only lock after the data is ready to be pushed and try to limit the push actions. 准备好要推送数据之后,至少要锁定并尝试限制推送操作。
If it's possible you can also increase the prioriy of the consumers. 如果可能,您还可以增加消费者的优先级。

By the way, this will not solve your immediate problem, but you can limit the number of notify_one() calls, because you only have to send one when the condition actually changes (not zero anymore to the consumer, not full anymore to the producer). 顺便说一句,这不能解决您眼前的问题,但是您可以限制notify_one()调用的次数,因为您只需要在条件实际改变时发送一个即可(不再向消费者发送零,不再向生产者发送满) )。

std::atomic<bool> producerShouldSleep = false;
std::atomic<bool> producerIsSleeping = false;

Item consumeItem(){ //consumer
    producerShouldSleep = true;
    while (!producerIsSleeping)
        yield();
    auto item = getItemFromQueue();
    producerShouldSleep = false;
    return item;
}

void produceData(){ //producer
    while (shouldBeRunning){
        if (producerShouldSleep){
            producerIsSleeping = true;
            while (producerShouldSleep)
                yield();
            producerIsSleeping = false;
            continue;
        }
        if (!queueIsFull())
            pushItemIntoQueue();
    }
}

This will give priority to the consumer. 这将优先考虑消费者。 Unless I screwed something up it will be correctly synchronized. 除非我搞砸了,否则它将正确同步。 The only problem I see is that the queue could be empty and someone calls consumeItem in a tight loop which may block the producer from pushing an item into the queue which ultimately causes a lifelock. 我看到的唯一问题是队列可能为空,并且有人在一个紧密的循环中调用consumeItem ,这可能会阻止生产者将项目推入队列,最终导致生命周期。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM