Я написал BlockingQueue для связи двух потоков.Можно сказать, что он следует шаблону «производитель-потребитель» с неограниченным буфером.Поэтому я реализовал его с помощью критического сечения и семафора, например:
#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 - это обертка RAII для CCriticalSection, она входит в нее при создании и оставляет ее при уничтожении.CSemaphore - это оболочка для семафора Windows.
Пока все хорошо, потоки отлично взаимодействуют.Однако, когда поток производителя прекращает производство и завершает работу, а поток потребителя потребляет все, поток потребителя остается навсегда зависшим от вызова Pop ().
Как я могу сказать, чтобы потребитель элегантно завершил работу?Я думал об отправке специального пустого элемента, но он кажется слишком небрежным.