| |
Scheduler调度的对象是一个个Event对象,比如Packet类就是Event类的派生类。先看Event类有什么: class Event { public: Event* next_; /* event list */ Event* prev_; Handler* handler_; /* handler to call when event ready */ double time_; /* time at which event is ready */ scheduler_uid_t uid_; /* unique ID */ Event() : time_(0), uid_(0) {} }; 可见,该类只有5个成员变量,最重要的是后面的三个。 Handler类是所有事件Handler的基类,当事件的调度时间到达时,该事件被传递给必须处理它的Handler。 class Handler { public: virtual ~Handler () {} virtual void handle(Event* event) = 0; }; 可见该类只有一个纯虚函数的虚基类,子类继承该类,使用handle()处理到时的事件。 现在看Scheduler类本身: class Scheduler : public TclObject { public: static Scheduler& instance() { return (*instance_); // general access to scheduler } void schedule(Handler*, Event*, double delay); // sched later event virtual void run(); // execute the simulator virtual void cancel(Event*) = 0; // cancel event virtual void insert(Event*) = 0; // schedule event virtual Event* lookup(scheduler_uid_t uid) = 0; // look for event virtual Event* deque() = 0; // next event (removes from q) virtual const Event* head() = 0; // next event (not removed from q) double clock() const { // simulator virtual time return (clock_); } virtual void sync() {}; virtual double start() { // start time return SCHED_START; } virtual void reset(); protected: void dumpq(); // for debug: remove + print remaining events void dispatch(Event*); // execute an event void dispatch(Event*, double); // exec event, set clock_ Scheduler(); virtual ~Scheduler(); int command(int argc, const char*const* argv); double clock_; int halted_; static Scheduler* instance_; static scheduler_uid_t uid_; }; 该类成员变量只有4个: uid_用来给Event分配uid,在scheduler.cc文件的一开始,该变量被初始化为1: scheduler_uid_t Scheduler::uid_ = 1; clock_和halted_在构造函数里被初始化为0:Scheduler::Scheduler() : clock_(SCHED_START), halted_(0) {} 宏SCHED_START在scheduler.h中定义为0:#define SCHED_START 0.0 /* start time (secs) */ 提供为外界的接口schedule()函数的主要部分: void Scheduler::schedule(Handler* h, Event* e, double delay) { ...... // a lot of checking e->uid_ = uid_++; // 给该Event分配id e->handler_ = h; // 给其指定处理者h,到时调用处理者h的handle()函数 e->time_ = clock_ + delay; // 指定该事件的触发时间,即时间戳 insert(e); // 将该事件插入列表中,使用什么样的列表,由Scheduler类的派生类来决定。 } Scheduler调度机制的引擎: void Scheduler::run() { instance_ = this; Event *p; while (!halted_ && (p = deque())) { dispatch(p, p->time_); } } 不断从列表中取出Event事件,调用dispatch()执行事件: void Scheduler::dispatch(Event* p, double t) { if (t clock_) { fprintf(stderr, "ns: scheduler going backwards in time from %f to %f./n", clock_, t); abort(); } clock_ = t; // 将系统的虚拟时钟设置为该事件的时间戳 p->uid_ = -p->uid_; // 将该Event的id变为相反数以标记它已被dispatch p->handler_->handle(p); // 具体将Event交给Handler来处理 } void Scheduler::dispatch(Event* p) { dispatch(p, p->time_); } 本文来自ChinaUnix博客,如果查看原文请点: http://blog.chinaunix.net/u1/33444/showart_272923.html | |
NS中Scheduler类的工作机制简述
