reference
summary
-
离散实践模拟器实现机制
-
Schedule 和 ScheduleWithContext()
Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj); Simulator::ScheduleWithContext (uint32_t context, Time const &time, MEM mem_ptr, OBJ obj);
context就是表明事件发生在哪个节点上面(不是具体某个节点发生的话,就会被设置为0xffffffff),就是全局的nodeID
-
当前正在执行的网络节点的节点 id 实际上由 Simulator 类跟踪。它可以通过 Simulator::GetContext 方法访问,该方法返回关联并存储在当前正在执行的事件中的“上下文”(一个 32 位整数)。在极少数情况下,当事件与特定网络节点无关时,其“上下文”设置为 0xffffffff。
原来如此,那以后debug的时候方便不少啊…
-
要将上下文与每个事件关联,Schedule 和 ScheduleNow 方法会自动重用当前正在执行的事件的上下文作为计划稍后执行的事件的上下文。
-
在某些情况下,尤其是在模拟从一个节点到另一个节点的数据包传输时,这种行为是不可取的,因为接收事件的预期上下文是接收节点的上下文,而不是发送节点的上下文。为了避免这个问题,Simulator 类提供了一个特定的调度方法:ScheduleWithContext,它允许显式提供与接收事件关联的接收节点的节点 ID。
-
手册里面还用 节点创建的场景 进行了举例,我找到了point-to-point-channel.cc的一个调用了ScheduleWithContext的函数
bool PointToPointChannel::TransmitStart ( Ptr<const Packet> p, Ptr<PointToPointNetDevice> src, Time txTime) { NS_LOG_FUNCTION (this << p << src); NS_LOG_LOGIC ("UID is " << p->GetUid () << ")"); NS_ASSERT (m_link[0].m_state != INITIALIZING); NS_ASSERT (m_link[1].m_state != INITIALIZING); uint32_t wire = src == m_link[0].m_src ? 0 : 1; Simulator::ScheduleWithContext (m_link[wire].m_dst->GetNode ()->GetId (), txTime + m_delay, &PointToPointNetDevice::Receive, m_link[wire].m_dst, p->Copy ()); // Call the tx anim callback on the net device m_txrxPointToPoint (p, src, m_link[wire].m_dst, txTime, txTime + m_delay); return true; }
-
-
可用的模拟器引擎
- 单线程的
- 分布式的
-
Simulator::run() & Simulator::stop() & Simulator::destroy() 之间的联系和区别
之前一直没有搞清楚什么时候stop什么时候destroy,趁现在整理一下。
常见的ns3主函数里面这么组织逻辑:int main(int argc, char *argv[]) { /* topo build logi NodeContainer nodes = buildTopo(openGym, startTime); buildApps(nodes); */ Simulator::Run(); Simulator::Destroy(); return 0; }
- Simulator::Run()
在这个函数调用之前,用户一般会利用Simulator::ScheduleI()和Simulator::ScheduleWithContext()将事件压栈,这个函数就是开始消耗栈内事件。 - Simulator::Stop()
不管Scheduler的队列里面还有多少事件没有完成,手上的事件完成后,立马执行这个停止事件,剩下的也不执行了,return to the caller 。 - Simulator::Destroy()
看到这个名字就想到析构函数吧,其实作用也是类似的,释放一些内存。
- Simulator::Run()