SimulatorImpl

class SimulatorImpl : public Object
{
public:
//仿真结束的时候调用
virtual void Destroy () = 0;
//检查是否事件队列空或者仿真结束时间到
virtual bool IsFinished (void) const = 0;
virtual void Stop (void) = 0;
virtual void Stop (Time const &time) = 0;
 virtual EventId Schedule (Time const &time, EventImpl *event) = 0;
 virtual void ScheduleWithContext (uint32_t context, Time const &time, EventImpl *event) = 0;
 virtual EventId ScheduleNow (EventImpl *event) = 0;
 virtual EventId ScheduleDestroy (EventImpl *event) = 0;
 virtual void Remove (const EventId &id) = 0;
 //设置对应时间的calcel bit,使得对应的函数不会被执行。有了remove,为什么还要用这个呢
 virtual void Cancel (const EventId &id) = 0;
 //检查事件是否执行过或者已经被取消
  virtual bool IsExpired (const EventId &id) const = 0;
  virtual void Run (void) = 0;
  virtual Time Now (void) const = 0;
  virtual Time GetDelayLeft (const EventId &id) const = 0;
  virtual Time GetMaximumSimulationTime (void) const = 0;
   virtual void SetScheduler (ObjectFactory schedulerFactory) = 0;
   //不知干嘛用的
    virtual uint32_t GetSystemId () const = 0; 
     virtual uint32_t GetContext (void) const = 0;
};

DefaultSimulatorImpl

想不通的

  • 带Context的事件怎么ScheduleNow呢

类型定义

struct EventWithContext {
    uint32_t context;
    uint64_t timestamp;
    EventImpl *event;
  };
  typedef std::list<struct EventWithContext> EventsWithContext;
typedef std::list<EventId> DestroyEvents;

数据成员

关于m_unscheduledEvents

用于记录已经插入Scheduler的但是没有被Process的事件。当有事件插入到Scheduler的map时该值加1,当有事件被取出执行的时候该值减1.
- 使其值变大的成员函数
- Schedule
- ScheduleNow
- ScheduleWithContext:当系统线程为主线程,直接把事件插入Scheduler的Map中的情况下
- ProcessEventWithContext:在需要将eventsWithContext中的事件(在别的非主线程生成的有Context的事件)插入到Scheduler的map中的时候。
- 使其值变小的成员函数
- ProcessOne
- Remove

关于m_currentContext
  • 构造函数中赋值为0xffffffff
  • ProcessOne中被设置为Scheduler的Map的队首事件的Context
  • 在GetContext()函数中被返回,函数被调用的地方:
    • Schedule中,函数返回结果用于设置新事件的Context
    • Schedulenow函数类似
      那到底是怎么个运行流程呢,假设一直都是主线程。那么是否可以理解:
      对于Schedule函数,新Schedule进来的事件的Context设置为与最近一个执行的事件的Context相同。直到新执行的事件的context发生改变或者
关于m_eventsWithContextEmpty
  • 构造函数中赋值为true
  • 在SchedulerWithContext中,如果系统线程不是main线程,将事件放入m_eventsWithContext,并将m_eventsWithContextEmpty设为false
  • 在ProcessEventsWithContext()中,如果m_eventsWithContext非空,则取出其中事件处理,并将该值设为true
EventsWithContext m_eventsWithContext;
bool m_eventsWithContextEmpty;
SystemMutex m_eventsWithContextMutex;
DestroyEvents m_destroyEvents;//存放一些需要在Destroy时执行的事件的EventId,初始化的时候是空的
bool m_stop;
Ptr<Scheduler> m_events;
uint32_t m_uid;
uint32_t m_currentUid;
uint64_t m_currentTs;
uint32_t m_currentContext;
int m_unscheduledEvents;
 SystemThread::ThreadId m_main;
};

成员函数

构造函数
DefaultSimulatorImpl::DefaultSimulatorImpl ()
{
  m_stop = false;
  // uids are allocated from 4.
  // uid 0 is "invalid" events
  // uid 1 is "now" events
  // uid 2 is "destroy" events
  m_uid = 4;
  // before ::Run is entered, the m_currentUid will be zero
  m_currentUid = 0;
  m_currentTs = 0;
  m_currentContext = 0xffffffff;
  m_unscheduledEvents = 0;
  m_eventsWithContextEmpty = true;
  m_main = SystemThread::Self();
}
DoDispose
  while (!m_events->IsEmpty ())
    {
      Scheduler::Event next = m_events->RemoveNext ();
      next.impl->Unref ();
    }
  m_events = 0;
  SimulatorImpl::DoDispose ();//SimulatorImpl中并没有复写DoDispose,因此此处调用的是其基类Object的DoDispose
Destroy

EventImpl::Invoke:如果状态为非取消状态,则调用EventImpl::Notify(实际上就是表征事件的对应函数
想不通的地方:
- 事件到底是在调用SimulatorImpl::ScheduleDestroy时加入到m_destroyEvents的。而m_destroyEvents就是用于存放一些需要在Destroy时执行的事件。

  while (!m_destroyEvents.empty ()){
      Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
      m_destroyEvents.pop_front ();
      if (!ev->IsCancelled ())
          ev->Invoke ();
    }
ProcessOneEvent

事件有序执行的重要函数,取出scheduler头部的事件并推进仿真时间。

  Scheduler::Event next = m_events->RemoveNext ();
  m_unscheduledEvents--;
  m_currentTs = next.key.m_ts;
  m_currentContext = next.key.m_context;
  m_currentUid = next.key.m_uid;
  next.impl->Invoke ();//调用 next.impl->Notify
  next.impl->Unref ();
  ProcessEventsWithContext ();
ProcessEventsWithContext
  if (m_eventsWithContextEmpty)
      return;
  // swap queues
  EventsWithContext eventsWithContext;
  {
    CriticalSection cs (m_eventsWithContextMutex);
    m_eventsWithContext.swap(eventsWithContext);//交换两个list的内容,而交换之前eventsWithContext是空的
    m_eventsWithContextEmpty = true;
  }
  while (!eventsWithContext.empty ()){
       EventWithContext event = eventsWithContext.front ();
       eventsWithContext.pop_front ();
       Scheduler::Event ev;
       ev.impl = event.event;
       ev.key.m_ts = m_currentTs + event.timestamp;
       ev.key.m_context = event.context;
       ev.key.m_uid = m_uid;
       m_uid++;
       m_unscheduledEvents++;
       m_events->Insert (ev);
    }
Run

一开是就调用 ProcessEventsWithContext ()到底是什么意思嘛~~

  m_main = SystemThread::Self();
  ProcessEventsWithContext ();
  m_stop = false;
  while (!m_events->IsEmpty () && !m_stop) {
      ProcessOneEvent ();
    }
Schedule

m_uid初始值为4。此后在每一次schedule的时候将其赋给event的key的m_uid,然后自增1,实现了每个事件m_uid的唯一性。

**想不清楚的地方:
为什么insert进来的Event的Context的值是DefaultSimulatorImpl的m_currentContext呢?这个值又是什么时候改变的??**

EventId DefaultSimulatorImpl::Schedule (Time const &time, EventImpl *event)
{
 //TimeStep()将uint64_t转换成Time结构
  Time tAbsolute = time + TimeStep (m_currentTs);
  Scheduler::Event ev;
  ev.impl = event;
  ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
  ev.key.m_context = GetContext ();
  ev.key.m_uid = m_uid;
  m_uid++;
  m_unscheduledEvents++;
  m_events->Insert (ev);
  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
}
ScheduleWithContext
  • 如果是m_main线程的话,直接根据函数创建相应的Event(对应设置先关的Context)然后插入Scheduler的队列中。
  • 如果SystemThread不是m_main的话,则生成一个EventWithContext (其中包含时间戳,EventImp,和context)的对象ev。将ev插入m_eventsWithContext中。
  • 看不懂的地方:什么时候分别是这两种情况呢??
void DefaultSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &time, EventImpl *event)
{
  if (SystemThread::Equals (m_main))
    {
      Time tAbsolute = time + TimeStep (m_currentTs);
      Scheduler::Event ev;
      ev.impl = event;
      ev.key.m_ts = (uint64_t) tAbsolute.GetTimeStep ();
      ev.key.m_context = context;
      ev.key.m_uid = m_uid;
      m_uid++;
      m_unscheduledEvents++;
      m_events->Insert (ev);
    }
  else
    {
      EventWithContext ev;
      ev.context = context;
      ev.timestamp = time.GetTimeStep ();
      ev.event = event;
      {
        CriticalSection cs (m_eventsWithContextMutex);
        m_eventsWithContext.push_back(ev);
        m_eventsWithContextEmpty = false;
      }
    }
}
ScheduleNow

为什么事件的uid不统一定成1呢?就像ScheduleDestroy那个样子。

Scheduler::Event ev;
  ev.impl = event;
  ev.key.m_ts = m_currentTs;
  ev.key.m_context = GetContext ();
  ev.key.m_uid = m_uid;
  m_uid++;
  m_unscheduledEvents++;
  m_events->Insert (ev);
  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
ScheduleDestroy

Schedule一些需要在调用Simulator::Destroy时执行的事件,IidManager的单例销毁就用了这个
- 在Dstroy时执行的事件的id统一定为2.但是整体计数的m_uid仍需自增

 EventId id (Ptr<EventImpl> (event, false), m_currentTs, 0xffffffff, 2);
  m_destroyEvents.push_back (id);
  m_uid++;
  return id;
IsExpired
判断相应的事件是否失效
bool 
DefaultSimulatorImpl::IsExpired (const EventId &id) const
  • uid为2(Destroy事件)
    • 能在m_destroyEvents中找到,则未失效,返回false。
    • 其他情况:失效
  • uid不为2时满足如下条件即为失效,返回true
    • id.PeekEventImpl () == 0
    • id.GetTs () < m_currentTs
    • id.GetTs () == m_currentTs && id.GetUid () <= m_currentUid
    • id.PeekEventImpl ()->IsCancelled ()
该函数被调用的地方:
  • GetDelayLeft
if (IsExpired (id))     return TimeStep (0);
  • Remove
    如果已经失效,则不进行任何操作
  • Cancel
if (!IsExpired (id))    id.PeekEventImpl ()->Cancel ();
GetContext
uint32_t DefaultSimulatorImpl::GetContext (void) const{
  return m_currentContext;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值