NS事件调度器

NS是一个基于事件驱动的单线程模拟器,在模拟器中有四种可使用的调度器:链表调度器、堆调度器、日历调度器和实时调度器。调度器调度的是事件,下面是事件的定义(event):

class Event {
public:
	Event* next_;	         /*事件链表*/
	Event* prev_;
	Handler* handler_;	/* 处理事件时的句柄 */
	double time_;		/* 事件执行的时间 */
	scheduler_uid_t uid_;	/* 全局唯一ID */
	Event() : time_(0), uid_(0) {} /*构造函数*/
};
当事件的调度时间到达时,该事件被传递给它的句柄来处理。下面是调度器类本身:

class Scheduler : public TclObject {
public:
	static Scheduler& instance() {
		return (*instance_);		// 通用调度器入口
	}
	void schedule(Handler*, Event*, double delay);	// 事件调度器
	virtual void run();			// 执行模拟
	virtual void cancel(Event*) = 0;	// 删除事件
	virtual void insert(Event*) = 0;	// 将事件插入队列
	virtual Event* lookup(scheduler_uid_t uid) = 0;	// 寻找事件
	virtual Event* deque() = 0;		// 出队
	virtual const Event* head() = 0;	// 下一个事件
	double clock() const {			// 仿真的虚拟时间
		return (clock_);
	}
	virtual void sync() {};
	virtual double start() {		// 开始时间
		return SCHED_START;
	}
	virtual void reset();
protected:
	void dumpq();	// for debug: 移除并打印剩下的事件
	void dispatch(Event*);	// 执行一个事件
	void dispatch(Event*, double);	//执行事件,设定时间
	Scheduler();
	virtual ~Scheduler();
	int command(int argc, const char*const* argv);
	double clock_;
	int halted_;
	static Scheduler* instance_;
	static scheduler_uid_t uid_;
};
举个例子:假设在aodv.cc里执行:

Scheduler::instance().schedule(this, &intr, HELLO_INTERVAL);
它会执行common\scheduler.cc里面的schedule()函数:

void 
Scheduler::schedule(Handler* h, Event* e, double delay)
{
	//如果未设置句柄,退出
	if (!h) {
		fprintf(stderr,
			"Scheduler: attempt to schedule an event with a NULL handler."
			"  Don't DO that.\n");
		abort();
	};
	if (e->uid_ > 0) {//事件ID出错,退出
		printf("Scheduler: Event UID not valid!\n\n");
		abort();
	}
	
	if (delay < 0) {
		// You probably don't want to do this
		// (it probably represents a bug in your simulation).
		fprintf(stderr, 
			"warning: ns Scheduler::schedule: scheduling event\n\t"
			"with negative delay (%f) at time %f.\n", delay, clock_);
	}

	if (uid_ < 0) {
		fprintf(stderr, "Scheduler: UID space exhausted!\n");
		abort();
	}
	e->uid_ = uid_++;
	e->handler_ = h;
	double t = clock_ + delay;

	e->time_ = t;
	insert(e);//插入调度队列
}

insert()函数将事件插入调度队列,等待执行,NS默认使用的是日历调度器:

void 
CalendarScheduler::insert(Event* e)
{
	int i;
	if (cal_clock_ > e->time_) {
		// may happen in RT scheduler
		cal_clock_ = e->time_;
		i = lastbucket_ = CALENDAR_HASH(cal_clock_);
	} else
		i = CALENDAR_HASH(e->time_);

	Event *head = buckets_[i].list_;
	Event *before=0;

	if (!head) {
		buckets_[i].list_ = e;
		e->next_ = e->prev_ = e;
		++stat_qsize_; 
		++buckets_[i].count_;
	} else {
		bool newhead;
		if (e->time_ >= head->prev_->time_) {
			// insert at the tail
			before = head;
			newhead = false;
		} else {
			// insert event in time sorted order, FIFO for sim-time events
			for (before = head; e->time_ >= before->time_; before = before->next_)
				;
			newhead = (before == head);
		}

		e->next_ = before;
		e->prev_ = before->prev_;
		before->prev_ = e;
		e->prev_->next_ = e;
		if (newhead) {
			buckets_[i].list_ = e;
			//assert(e->time_ <= e->next_->time_);
		}
		//assert(e->prev_ != e);
		if (e->prev_->time_ != e->time_) {
			// unique timing
			++stat_qsize_; 
			++buckets_[i].count_;
		}
	}
	++qsize_;
	//assert(e == buckets_[i].list_ ||  e->prev_->time_ <= e->time_);
	//assert(e == buckets_[i].list_->prev_ || e->next_->time_ >= e->time_);

  	if (stat_qsize_ > top_threshold_) {
  		resize(nbuckets_ << 1, cal_clock_);
		return;
	}
}

run函数会不断的在队列中取出事件执行:

void
Scheduler::run()
{
	instance_ = this;
	Event *p;
	while (!halted_ && (p = deque())) {
		dispatch(p, p->time_);
	}
}
取出队首事件,如果队列不为空,则调用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_;	// 事件已经被处理了,标为负
	p->handler_->handle(p);	// 调用事件的handle()函数
}
最后一句调用了用户自己定义了handle函数:

void
NeighborTimer::handle(Event*) {
  agent->nb_purge();
  Scheduler::instance().schedule(this, &intr, HELLO_INTERVAL);
}
如此便完成了定时执行的功能。





posted @ 2012-06-04 15:41  应律  阅读(232)  评论(0编辑  收藏  举报