【发布时间】:2023-03-23 13:05:01
【问题描述】:
又是我和我的 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
因为 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
}
【问题讨论】:
-
当你有一个互斥体时,为什么你需要互锁的递增/递减?
-
询问队列大小。我没有发布它,但是有一个 getter 方法
-
等等,还有另一个更重要的原因:唤醒在空队列中阻塞的待处理 Pop 呼叫。查看 Push() 的最后几行
-
你不需要那种连锁魔法。无论如何,您都可以在您命中的关键部分内获得该大小而无需互锁操作。
-
... 你崩溃了,因为你没有检查
pNewHeadNode是否不是 NULL 以防你的队列为空:)
标签: c++ concurrency race-condition blockingqueue