这是我和我的BlockingQueue ......我根据this article和this question重写了它。它会发送一些项目,然后因访问冲突而崩溃。这是代码:
template <typename T>
bool DRA::CommonCpp::CTBlockingQueue<T>::Push( T pNewValue ){
volatile long oldSize;
::InterlockedExchange( &oldSize, m_Size );
CTNode* pNewNode = new CTNode();
pNewNode->m_pValue = pNewValue;
{//RAII block
CGuard g( m_TailCriticalSection );
m_pTailNode->m_pNext = pNewNode;
m_pTailNode = pNewNode;
::InterlockedIncrement( &m_Size );
}
if( oldSize == 0 )
m_eAtLeastOneElement.set();
return true;
}
template <typename T>
bool DRA::CommonCpp::CTBlockingQueue<T>::Pop( T& pValue ){
CTNode* pCurrentNode;
{//RAII block
CGuard g( m_HeadCriticalSection );
pCurrentNode = m_pHeadNode;
CTNode* pNewHeadNode = m_pHeadNode->m_pNext;
if( pNewHeadNode == NULL ){
CEvent* pSignaledEvent;
CEvent::waitForPair( m_eAtLeastOneElement, m_eFinished, pSignaledEvent );
if( pSignaledEvent == &m_eFinished )
return false;
pNewHeadNode = m_pHeadNode->m_pNext;
}
pValue = pNewHeadNode->m_pValue;
m_pHeadNode = pNewHeadNode;
::InterlockedDecrement( &m_Size );
}
delete pCurrentNode;
return true;
}
它总是在调用Pop()之后崩溃,在if之后的行中,那个说:
pValue = pNewHeadNode->m_pValue
它炸毁cos'pNewHeadNode为NULL。但是这怎么可能发生呢?
编辑:忘记初始化代码:
template <typename T>
DRA::CommonCpp::CTBlockingQueue<T>::CTBlockingQueue():
m_HeadCriticalSection("CTBlockingQueue<T>::m_Head"),
m_TailCriticalSection("CTBlockingQueue<T>::m_Tail"){
CTNode* pDummyNode = new CTNode();
m_pHeadNode = pDummyNode;
m_pTailNode = pDummyNode;
m_Size = 0; //Dummy node doesn't count
}
答案 0 :(得分:1)
我的假设必须是事件被设置在关键部分之外,这意味着push可能会通知事件两次。您是否尝试过在关键部分内设置事件?
答案 1 :(得分:0)
最后,我回到原来的,效率较低的实现,即我发布here的实现,添加了一个Finish()方法,以便生产者可以发信号通知消费者优雅地结束,一个Restart()方法,可以在不破坏和重新创建队列的情况下再次开始生成:
//Template definitions
template<class Element>
DRA::CommonCpp::CTBlockingQueue<Element>::CTBlockingQueue( unsigned int maxSize ):
m_csFinished( "CTBlockingQueue::m_csFinished" ),
m_csQueue( "CTBlockingQueue::m_csQueue" ),
m_semElementCount( 0, maxSize ),
m_bFinished(false){
}
template<class Element>
DRA::CommonCpp::CTBlockingQueue<Element>::~CTBlockingQueue(){
Finish();
}
template<class Element>
void DRA::CommonCpp::CTBlockingQueue<Element>::Push( Element newElement ){
{//RAII block
CGuard g( m_csQueue );
m_Queue.push( newElement );
}
m_semElementCount.Signal();
}
template<class Element>
bool DRA::CommonCpp::CTBlockingQueue<Element>::Pop( Element& element ){
m_semElementCount.Wait();
{//RAII block
CGuard g( m_csFinished );
if( m_bFinished ){
CGuard g( m_csQueue );
if ( m_Queue.size() == 0 )
return false;
}
}
{//RAII block
CGuard g( m_csQueue );
element = m_Queue.front();
m_Queue.pop();
}
return true;
}
template<class Element>
void DRA::CommonCpp::CTBlockingQueue<Element>::Finish(){
{//RAII block
CGuard g( m_csFinished );
m_bFinished = true;
}
{//RAII block
CGuard g( m_csQueue );
m_semElementCount.Signal();
}
}
template<class Element>
void DRA::CommonCpp::CTBlockingQueue<Element>::Restart(){
{//RAII block
CGuard g( m_csFinished );
m_bFinished = false;
}
}
这不是最快的方式,但对我来说工作得足够快。