首页 > 技术文章 > Ceph剖析:定时器safetimer的实现

shanno 2014-09-09 16:25 原文

定时器的作用是在指定的时间执行指定的动作。SafeTimer通过multimap数据结构维护定时项,定时项是时间和事件的Pair,定时项在map中按照定时时间从小到大排列。此外,SafeTimer使用一个线程来轮询定时项,当到达定时项指定的时间时执行对应的事件。下面代码是这个线程的入口函数:

void SafeTimer::timer_thread()
{
   lock.Lock();
   while (!stopping) {
	utime_t now = ceph_clock_now(cct); /// 获取当前时间
    
	while (!schedule.empty()) {
	  scheduled_map_t::iterator p = schedule.begin();

	  /// 还没达到指定的定时时间
          /// 因为schedule中的定时项是已经排好顺序的,第1个元素就是最先要处理的事件,所以只要检查第1个元素就可以了
	  if (p->first > now) { 
		  break;
	  }

	  /// 处理指定的事件
	  Context *callback = p->second;
	  events.erase(callback);
	  schedule.erase(p);
	  
	  if (!safe_callbacks){
           lock.Unlock();
	  }
   
          /// 处理事件时,解锁。因为处理事件不会修改定时器本身的数据
	  callback->complete(0);
	  if (!safe_callbacks){
		  lock.Lock();
	  }
	}

	/// 当使用者向schedule插入新的定时项时,如果新的定时项的时间是最早的,那么它会唤醒该线程
	if (schedule.empty()) {
		cond.Wait(lock);
	} else {
		/// 等待指定的时间
		cond.WaitUntil(lock, schedule.begin()->first);
        }
   }
  lock.Unlock();
}

定时器实现考虑以下几个因素:1) 定时项按照从早到晚排序,通过std::multimap实现;2) 修改定时器相关的数据时加锁,执行定时动作前解锁。这样就不会阻塞其它线程对定时器的操作,例如添加、删除定时项;3) 当新加入的定时项位于队列头部时,唤醒定时线程。

推荐阅读