Безопасна ли эта реализация блокирующей очереди?

Я пытаюсь реализовать очередь, которая блокирует операцию Pop, если она пуста, и разблокируется, как только будет нажат новый элемент. Боюсь, что у меня может быть какое-то состояние гонки; Я попытался рассмотреть некоторые другие реализации, но большинство из них было найдено в .NET, и несколько C ++, которые я нашел, слишком сильно зависели от других classов библиотек.

template  class BlockingQueue{ DRA::CommonCpp::CCriticalSection m_csQueue; DRA::CommonCpp::CEvent m_eElementPushed; std::queue 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 – это shell для критического раздела Windows, методы Enter и Leave являются частными, а CGuard – его единственным другом
  • CGuard является оболочкой RAII для CCriticalSection, входит в критический раздел конструктора, оставляет его на деструкторе
  • CEvent – это shell для события Windows, wait использует функцию WaitForSingleObject
  • Я не против, что Элементы передаются по значению, это небольшие объекты
  • Я не могу использовать Boost, просто материал Windows (как я уже делал с CEvent и CGuard)

Я боюсь, что при использовании Pop () может возникнуть какой-то странный сценарий условий гонки. Ребята, что вы думаете?

UPDATE : Поскольку я работаю над Visual Studio 2010 (.NET 4.0), я закончил использование classа unbounded_buffer, предоставленного средой выполнения C ++. Конечно, я завернул его в class, используя указатель на Idiom для реализации (Chesire Cat), на случай, если мы решим изменить реализацию или нужно перенести этот class в другую среду

Это не streamобезопасность:

  {//RAII block CGuard g( m_csQueue ); bool wait = m_Queue.empty(); } /// BOOM! Other thread ninja-Pop()s an item. if( wait ) m_eElementPushed.wait(); 

Обратите внимание на местоположение комментария BOOM . На самом деле, другие места также мыслимы (после if ). В любом случае последующие front и pop вызовы не будут выполнены.

Переменные условия должны быть полезны, если вы нацеливаете новейшие версии Windows. Это обычно упрощает реализацию очередей блокировки.

См. Здесь для создания аналогичной очереди с использованием Boost – даже если вы не можете использовать переменные Boost или условия, общее руководство и последующее обсуждение должны быть полезными.