Я пытаюсь реализовать очередь, которая блокирует операцию Pop, если она пуста, и разблокируется, как только новый элемент помещается.Боюсь, у меня может быть какое-то состояние гонки;Я попытался взглянуть на какую-то другую реализацию, но большинство из найденных мной было сделано в .NET, и несколько найденных мной C ++ слишком сильно зависели от других библиотечных классов.
template <class Element>
class BlockingQueue{
DRA::CommonCpp::CCriticalSection m_csQueue;
DRA::CommonCpp::CEvent m_eElementPushed;
std::queue<Element> m_Queue;
public:
void Push( Element newElement ){
CGuard g( m_csQueue );
m_Queue.push( newElement );
m_eElementPushed.set();
}
Element Pop(){
{//RAII block
CGuard g( m_csQueue );
bool wait = m_Queue.empty();
}
if( wait )
m_eElementPushed.wait();
Element first;
{//RAII block
CGuard g( m_csQueue );
first = m_Queue.front();
m_Queue.pop();
}
return first;
}
};
Должны быть некоторые объяснения:
- CCriticalSection - это оболочка для критического раздела Windows, методы Enter и Leave являются частными, а CGuard - его единственный друг
- CGuard - это оболочка RAII для CCriticalSection, входит в критический раздел на конструкторе, оставляетэто на деструкторе
- CEvent - оболочка для события Windows, wait использует функцию WaitForSingleObject
- Я не против, чтобы элементы передавались по значению, они являются маленькими объектами
- Я не могу использовать Boost, только что-то для Windows (как я уже делал с CEvent и CGuard)
Боюсь, что при использовании Pop () может возникнуть какой-то странный сценарий состояния гонки.,Что вы, ребята, думаете?
ОБНОВЛЕНИЕ : Поскольку я работаю над Visual Studio 2010 (.NET 4.0), я в конечном итоге использовал класс unbounded_buffer, предоставляемый средой выполнения C ++.Конечно, я обернул его в класс с помощью идиомы указателя на реализацию (Chesire Cat) на тот случай, если мы решим изменить реализацию или нужно перенести этот класс в другую среду