为什么这不是正确的生产者消费者模型以及当我使用 stl 队列时导致错误的原因

why this is not a right Producer consumer model and what causes the error when I use stl queue?

本文关键字:队列 stl 错误 生产者 这不是 消费者 模型 为什么      更新时间:2023-10-16

应用程序在行delete busMsg运行一段时间后会出现错误。我不明白错误是如何产生的。

#include "stdafx.h"
#include "queue.h"
#include <queue>
#include <iostream>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
CWinApp theApp;
using namespace std;
CRITICAL_SECTION  m_csReceivedMsgQueue;
HANDLE    m_hReceivedDataEvent;
HANDLE  m_hEventStop;
queue<CBusMsg* > m_qReceivedMsgQueue;
class CBusMsg
 {
    public:
    CBusMsg(WORD  nAgentID, WORD nAgentExclue,  BYTE* pBuf,int nLen)
    {
       m_nAgentID=nAgentID;
       m_nAgentExclue=nAgentExclue;
       m_nLen=nLen;
       m_pBuf=new BYTE[m_nLen];
       memcpy(m_pBuf,pBuf,nLen);
    }
   ~CBusMsg()
   {
       if (m_pBuf!=NULL)
          delete[] m_pBuf;
   }
   WORD  m_nAgentID;   //0:群发,其它:单播
   WORD  m_nAgentExclue;   
   BYTE* m_pBuf;
   int   m_nLen;
};
UINT SendhreadProc( LPVOID pParam)
{   
    HANDLE  hWaitObjList[2]={m_hEventStop,m_hReceivedDataEvent};
    bool haveData = false;
    DWORD dwWaitRes;
    for(;;)
     {
        if(haveData)//如果还有未处理的数据不等待内核对象直接返回
        {
          dwWaitRes=::WaitForMultipleObjects(2,hWaitObjList,FALSE,0);   
        }
        else//如果没有未处理的数据不等待内核对象直接返回
        {
        dwWaitRes=::WaitForMultipleObjects(2,hWaitObjList,FALSE,200);   
        }
        if((dwWaitRes-WAIT_OBJECT_0)==0)//,索引为0的内核对象被触发,也就是停止线程被触发
       {
           break;
       }
        haveData = false;
       try
       {
           EnterCriticalSection(&m_csReceivedMsgQueue);
           if(m_qReceivedMsgQueue.empty())
          {
            LeaveCriticalSection(&m_csReceivedMsgQueue);
            continue;
          }
        CBusMsg*& busMsg = m_qReceivedMsgQueue.front();//取队首元素
        m_qReceivedMsgQueue.pop();//弹出队首元素
        if(NULL==busMsg)
        {
            LeaveCriticalSection(&m_csReceivedMsgQueue);
            continue;
        }
        //ASSERT(busMsg->m_nLen<=0);
        //pAgent->SetData(busMsg->m_pBuf,busMsg->m_nLen);
        haveData = !m_qReceivedMsgQueue.empty();
        LeaveCriticalSection(&m_csReceivedMsgQueue);
        //**************There is the error********************/
        delete busMsg;
       //********************************************************/
        //busMsg = NULL;
        //ProcessData(pAgent);
    }
    catch(...)
    {
        LeaveCriticalSection(&m_csReceivedMsgQueue);
    }
}
//delete pAgent;
return 0;
}

UINT PushData( LPVOID pParam)
{
BYTE pPacket[1000];
memset(pPacket,0,1000);
for (int i=0;i<100000;i++)
{
    CBusMsg *pBusMsg;
    pPacket[0]= i;
    pBusMsg=new CBusMsg(i,0,pPacket,1000);
    TRACE("请求向队列加消息n");
    EnterCriticalSection(&m_csReceivedMsgQueue);
    TRACE("开始向队列加消息n");
    m_qReceivedMsgQueue.push(pBusMsg);
    LeaveCriticalSection(&m_csReceivedMsgQueue);
    SetEvent(m_hReceivedDataEvent);
}
return 0;
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    int nRetCode = 0;
    InitializeCriticalSection(&m_csReceivedMsgQueue);
    HMODULE hModule = ::GetModuleHandle(NULL);

    m_hReceivedDataEvent =::CreateEvent(NULL,FALSE,FALSE,NULL);
    m_hEventStop=::CreateEvent(NULL,FALSE,FALSE,NULL);
    //创建发送线程
    CWinThread*  m_pSendThread=AfxBeginThread(SendhreadProc,NULL,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL);
    m_pSendThread->m_bAutoDelete=FALSE;
    m_pSendThread->ResumeThread();
    CWinThread*  processThread=AfxBeginThread(PushData,NULL,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL);
    processThread->m_bAutoDelete=FALSE;
    processThread->ResumeThread();
    char str[1000];
    cin.getline(str,900);
    return nRetCode;
}

问题可能在这里

CBusMsg*& busMsg = m_qReceivedMsgQueue.front();//取队首元素
m_qReceivedMsgQueue.pop();//弹出队首元素

从队列中获取对指针的引用。然后,您弹出队列,使引用无效。这将使程序崩溃几次。这可能会让你更快乐

CBusMsg* busMsg = m_qReceivedMsgQueue.front();//取队首元素
m_qReceivedMsgQueue.pop();//弹出队首元素

为什么它会崩溃,因为引用的地址可能会在您到达之前被重用于其他内容

delete busMsg;

您在删除之前释放锁,在这段时间内,另一个人可以使用相同的地址将新的东西放入队列中,例如,如果队列在.pop后为空。然后,删除操作不会删除原始引用的消息,而是删除它引用的新消息。