VeinsInet节点定位停止报错:send()/sendDelayed()无法发送inet::Packet
解决OMNeT++中send()/sendDelayed()数据包持有报错问题
问题根源
你说没在callRefreshDisplay()里发送数据包,但看你贴的代码,这个方法里明确调用了sendPacket(std::move(packet))——这就是触发报错的直接原因。
OMNeT++的callRefreshDisplay()是专门用于界面显示刷新的回调方法,它运行在模拟的"显示更新阶段",这个阶段不允许执行发送数据包、调度事件这类修改模拟状态的操作。此时数据包会被omnetpp::cDefaultList持有,调用send()自然会抛出错误。
解决方案
把发送数据包、停车的业务逻辑从callRefreshDisplay()中移出,放到OMNeT++标准的事件处理流程里,比如用周期性定时器检查位置:
添加定时器成员:在你的应用类中声明一个自消息定时器
class VeinsInetSampleApplication : public inet::ApplicationBase { // ... 已有成员 cMessage* positionCheckTimer; };初始化定时器:在
initialize()中调度周期性检查任务void VeinsInetSampleApplication::initialize(int stage) { ApplicationBase::initialize(stage); if (stage == INITSTAGE_APPLICATION_LAYER) { positionCheckTimer = new cMessage("positionCheckTimer"); scheduleAt(simTime() + 0.1, positionCheckTimer); // 每0.1秒检查一次位置 } }处理定时器事件:在消息处理方法中检查位置,执行业务逻辑
void VeinsInetSampleApplication::handleMessageWhenUp(cMessage* msg) { if (msg == positionCheckTimer) { checkPositionAndAct(); scheduleAt(simTime() + 0.1, positionCheckTimer); // 继续调度下一次检查 } // ... 处理其他消息逻辑 } void VeinsInetSampleApplication::checkPositionAndAct() { double pos1 = 128; double pos2 = 130; double pos3 = 103; double pos4 = 105; if (getParentModule()->getIndex() == 0) { auto currentPos = mobility->getCurrentPosition(); if (currentPos.x > pos1 && currentPos.x < pos2 && currentPos.y > pos3 && currentPos.y < pos4) { // 构造并发送事故数据包 auto payload = makeShared<VeinsInetSampleMessage>(); payload->setChunkLength(B(100)); payload->setRoadId(traciVehicle->getRoadId().c_str()); timestampPayload(payload); auto packet = createPacket("accident"); sendPacket(std::move(packet)); // 让车辆停止 traciVehicle->setSpeed(0); // 如果需要刷新界面,再调用callRefreshDisplay callRefreshDisplay(); } } }清理定时器:记得在
finish()中释放定时器资源void VeinsInetSampleApplication::finish() { cancelAndDelete(positionCheckTimer); ApplicationBase::finish(); }
注意事项
callRefreshDisplay()只应该用来做纯显示相关的操作,比如修改节点图标颜色(就是你注释掉的那行代码),不要在里面执行任何会改变模拟状态的逻辑。
内容的提问来源于stack exchange,提问作者amin rezaei
相关产品推荐
相关产品推荐

