访问违规阅读位置。堆腐败。提升线程

时间:2012-05-23 22:26:09

标签: c++ multithreading boost heap corruption

我正在尝试使用boost,raknet和irrlicht创建一个多线程图形网络应用程序。 我使用一个接收消息的线程和另一个线程来处理消息和所有图形工作。

这是我正在获取的错误屏幕

  

在0x77183c8d的第一次机会异常       NetSystemForVideogamesServerTester.exe:0xC0000005:访问冲突读取位置0x0d99d472

这是输出窗口信息

  

HEAP [NetSystemForVideogamesServerTester.exe]:HEAP:Free Heap block   da58d10在da58fe0被修复后被释放Windows触发了一个   NetSystemForVideogamesServerTester.exe中的断点。

     

这可能是由于堆的损坏,这表明存在错误   NetSystemForVideogamesServerTester.exe或它具有的任何DLL   加载。

     

这也可能是由于用户在按下F12时   NetSystemForVideogamesServerTester.exe具有焦点。

     

输出窗口可能包含更多诊断信息。

这是我启动线程的时候

void receive()
    {       
        boost::thread(&IConnectionInstance::receiveInThread, this);
    }

互斥声明

boost::mutex mMessagesReceived;

这是来自接收线程的代码

void RakNetConnectionInstance::receiveInThread()
{
    Packet* packet;
    IMessage* message = NULL;   
    long time = 0;

    while (true)
    {
        message = NULL;
        packet = aPeer->Receive();  

        while (packet)
        {           
            RakNet::BitStream* dataStream = new RakNet::BitStream(packet->data, packet->length, false);
            dataStream->IgnoreBits(sizeof(unsigned char)*8);    

            switch (packet->data[0])
            {               

            case ID_TIMESTAMP:
                {
                    dataStream->Read(time);
                    int countMessagesAggregated = 0;
                    dataStream->Read(countMessagesAggregated);
                    unsigned char messageType = char();

                    IBitStream* bitStream = new RakNetBitStream(dataStream);

                    while(countMessagesAggregated > 0)
                    {                       
                        dataStream->Read(messageType);

                        switch ((EMESSAGE_TYPE)messageType)
                        {
                        case EACTOR_CONTENT_MESSAGE:                            
                            message = new CActorContentMessage(aUserDataFactory);                           
                            break;
                        case EWORLD_CONTENT_MESSAGE:                            
                            message = new CWorldClientContentMessage(aUserDataFactory);                         
                            break;                                                  
                        case EUSER_COMMAND_MESSAGE: 
                            message = new CUserCommandMessage(aEventFactory);                           
                            break;
                        case EPREDICTION_MESSAGE:
                            message = new CPredictionMessage(aUserDataFactory);                         
                            break;
                        case EPREDICTION_RESPONSE_MESSAGE:
                            message = new CPredictionResponseMessage(aUserDataFactory);                     
                            break;
                        }

                        countMessagesAggregated --; 

                        if (messageType >= EUSER_MESSAGE && aCustomReceiver)
                        {
                            aCustomReceiver->receiveCustomMessages();
                        }

                        if (message)
                        {
                            message->readFromBitStream(bitStream);
                            message->setTimeMS(time);   
                            message->setIPAddress(packet->systemAddress.ToString(false));
                            message->setPort(packet->systemAddress.port);

                            mMessagesReceived.lock();
                            aMessagesReceivedQueue.push(message);
                            printf("adicionando mensaje a cola en lock\n");
                            mMessagesReceived.unlock();
                            message = NULL;
                        }
                    }                                       
                }
                break;
            }

            if (message)
            {
                message->setTimeMS(time);   
                message->setIPAddress(packet->systemAddress.ToString(false));
                message->setPort(packet->systemAddress.port);

                mMessagesReceived.lock();
                aMessagesReceivedQueue.push(message);
                mMessagesReceived.unlock();
            }

            aPeer->DeallocatePacket(packet);
            packet = aPeer->Receive();              
        }
        if (RakNet::GetTimeMS() - aBeginTimeSearchServersActives > aWaitTimeServersActives && !aTimeOut)
        {
            boost::mutex::scoped_lock lock(mTimeOut);
            aTimeOut = true;
        }
    }
}

这里我参加了处理过程中队列中的消息

void CMessageManager::attendMessages()
{   
    std::queue<IMessage*> messages = aConnectionInstance->getMessagesReceivedFromQueue();

    while(!messages.empty())
    {
        notifyMessage(messages.back());
        aConnectionInstance->popMessageReceivedFromQueue();     
        messages.pop();             
    }       
}

这里我访问消息队列

std::queue<IMessage*> RakNetConnectionInstance::getMessagesReceivedFromQueue()
{       
    boost::mutex::scoped_lock lock(mMessagesReceived);
    std::queue<IMessage*> messages; 
    messages = aMessagesReceivedQueue;
    return messages;
}

最后在这里我删除队列中的消息

void RakNetConnectionInstance::popMessageReceivedFromQueue()
{   
    boost::mutex::scoped_lock lock(mMessagesReceived);
    if (!aMessagesReceivedQueue.empty())
    {       
        aMessagesReceivedQueue.pop();               
    }
}

我是c ++和多线程的新手,请帮帮我,我做错了什么? 提前谢谢。

1 个答案:

答案 0 :(得分:0)

您不会从原始队列中删除消息,只需将指针复制到新队列即可。所以发生以下情况:

  1. 您收到一条消息。指向它的指针会进入队列。

  2. 您复制队列,处理邮件并将其删除。

  3. 您收到了另一条消息。

  4. 您复制队列。它仍然包含指向第一条消息的指针。

  5. 您可以访问指向您删除的第一条消息的指针。

  6. 此代码已损坏,因为它会复制队列而原始未修改:

    std::queue<IMessage*> RakNetConnectionInstance::getMessagesReceivedFromQueue()
    {       
        boost::mutex::scoped_lock lock(mMessagesReceived);
        std::queue<IMessage*> messages; 
        messages = aMessagesReceivedQueue;
        return messages;
    }