0

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

这是我得到的错误屏幕

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

这是输出窗口信息

HEAP[NetSystemForVideogamesServerTester.exe]:HEAP:释放堆块 da58d10 在 da58fe0 被释放后修改 Windows 已触发 NetSystemForVideogamesServerTester.exe 中的断点。

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

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

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

这是我启动线程的时候

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++ 和多线程的新手,请帮助我,我做错了什么?提前致谢。

4

1 回答 1

0

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

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

  2. 您复制队列、处理消息并将其删除。

  3. 您收到另一条消息。

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

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

此代码已损坏,因为它复制了未修改原始队列的队列:

std::queue<IMessage*> RakNetConnectionInstance::getMessagesReceivedFromQueue()
{       
    boost::mutex::scoped_lock lock(mMessagesReceived);
    std::queue<IMessage*> messages; 
    messages = aMessagesReceivedQueue;
    return messages;
}
于 2012-05-23T22:53:38.273 回答