阻止队列的这种实现安全吗?

dar*_*mos 5 c++ windows queue concurrency blocking

我正在尝试实现一个队列,如果它是空的,则阻塞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;
    }
};
Run Code Online (Sandbox Code Playgroud)

一些解释到期:

  • CCriticalSection是Windows Critical Section的包装器,Enter和Leave方法是私有的,CGuard是它唯一的朋友
  • CGuard是CCriticalSection的RAII包装器,在构造函数上输入关键部分,将它留在析构函数上
  • CEvent是Windows事件的包装器,wait使用WaitForSingleObject函数
  • 我不介意元素按值传递,它们是小对象
  • 我不能使用Boost,只是Windows的东西(因为我已经在使用CEvent和CGuard)

我担心使用Pop()时可能会出现一些奇怪的竞争情况.你们有什么感想?

更新:由于我正在使用Visual Studio 2010(.NET 4.0),我最终使用了C++运行时提供的unbounded_buffer类.当然,我使用Pointer to Implementation Idiom(Chesire Cat)将它包装在一个类中,以防我们决定更改实现或需要将此类移植到另一个环境

Kon*_*lph 9

这不是线程安全的:

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

注意BOOM评论的位置.事实上,其他地方也是可以想象的(之后if).在任何一种情况下,后续frontpop调用都将失败.