我写了一个BlockingQueue以便通信两个线程。您可以说它遵循Producer-Consumer模式,具有无限制的缓冲区。因此,我使用关键部分和信号量来实现它,如下所示:
#pragma once
#include "Semaphore.h"
#include "Guard.h"
#include <queue>
namespace DRA{
namespace CommonCpp{
template<class Element>
class BlockingQueue{
CCriticalSection m_csQueue;
CSemaphore m_semElementCount;
std::queue<Element> m_Queue;
//Forbid copy and assignment
BlockingQueue( const BlockingQueue& );
BlockingQueue& operator=( const BlockingQueue& );
public:
BlockingQueue( unsigned int maxSize );
~BlockingQueue();
Element Pop();
void Push( Element newElement );
};
}
}
//Template definitions
template<class Element>
DRA::CommonCpp::BlockingQueue<Element>::BlockingQueue( unsigned int maxSize ):
m_csQueue( "BlockingQueue::m_csQueue" ),
m_semElementCount( 0, maxSize ){
}
template<class Element>
DRA::CommonCpp::BlockingQueue<Element>::~BlockingQueue(){
//TODO What can I do here?
}
template<class Element>
void DRA::CommonCpp::BlockingQueue<Element>::Push( Element newElement ){
{//RAII block
CGuard g( m_csQueue );
m_Queue.push( newElement );
}
m_semElementCount.Signal();
}
template<class Element>
Element DRA::CommonCpp::BlockingQueue<Element>::Pop(){
m_semElementCount.Wait();
Element popped;
{//RAII block
CGuard g( m_csQueue );
popped = m_Queue.front();
m_Queue.pop();
}
return popped;
}
CGuard是CCriticalSection的RAII包装器,它在构造时进入,而在破坏时离开。 CSemaphore是Windows信号量的包装。
到目前为止,一切都很好,线程之间的通信非常完美。但是,当生产者线程停止生产并结束,并且消费者线程消耗了所有东西时,消费者线程永远卡在Pop()调用上。
我怎样才能告诉消费者优雅的结局?我曾想发送一个特殊的空元素,但它似乎太草率。
最佳答案
您最好使用事件而不是信号量。添加时,请锁定CS,并检查元素计数(存储到bIsEmpty
局部变量中)。添加到队列中,然后检查元素数是否为空,SetEvent
!
在pop方法上,首先锁定,然后检查它是否为空,然后检查WaitForSingleObject
-WFSO返回时,您会立即知道队列中至少有一项。
检查此article
关于c++ - C++模板化的Producer-Consumer BlockingQueue,无界缓冲区: How do I end elegantly?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6683356/