码迷,mamicode.com
首页 > 其他好文 > 详细

Libev学习笔记4

时间:2015-05-19 20:51:19      阅读:805      评论:0      收藏:0      [点我收藏+]

标签:

这一节分析Libev的定时器部分。对定时器的使用主要有两个函数:

ev_timer_init (&timeout_watcher, timeout_cb, 5.5, 0.);
ev_timer_start (loop, &timeout_watcher);

 

和ev_io类型的watcher类似,timeout_watcher是一个类型为ev_timer的watcher,上面的ev_timer_init函数将它设置为5.5秒之后调用回调函数timeout_cb,最后一个参数0表示定时器不重复超时,执行完一次回调函数后就停止计时,如果最后一个参数为非0,那么回调函数第一次执行完之后,每个指定秒后回调函数会被重复执行。将ev_timer结构体展开:

typedef struct ev_timer
{
  int active; /* private */            \     /* 非0表示watcher为激活状态,是periodics或timers数组的下标 */
  int pending; /* private */            \    /* 非0表示watcher中有事件被触发,是pendings数组的下标 */
  EV_DECL_PRIORITY /* private */        \    /* watcher的优先级 */
  EV_COMMON /* rw */                \        /* void *data; */
  EV_CB_DECLARE (type) /* private */         /* void (*cb)(EV_P_ struct type *w, int revents); */
  ev_tstamp at;

  ev_tstamp repeat; /* rw */
} ev_timer;

其中at成员对应倒数第二个参数,表示多少秒后第一次触发超时;repeat成员对应最后一个参数,表示第一次超时触发之后每个多少秒重复触发。ev_timer_init函数实质上就是设置上面这些成员。ev_timer_start主要工作是将timer放入最小堆中,由最小堆统一管理所有的timer,代码如下:

/* 计算定时器的绝对触发事件并放入堆中 */
void noinline
ev_timer_start (EV_P_ ev_timer *w) EV_THROW
{
  if (expect_false (ev_is_active (w)))
    return;

  ev_at (w) += mn_now;    /* 从现在开始经过at秒后触发 */++timercnt;
  ev_start (EV_A_ (W)w, timercnt + HEAP0 - 1);

  /* 将定时器w放入timers堆中 */
  array_needsize (ANHE, timers, timermax, ev_active (w) + 1, EMPTY2);
  ANHE_w (timers [ev_active (w)]) = (WT)w;
  ANHE_at_cache (timers [ev_active (w)]);

  /* 更新heap */
  upheap (timers, ev_active (w));
}

代码首先根据当前时间计算timer超时时刻的绝对时间,然后增加loop管理的timer个数timercnt,修改一些标志变量,最后把timer放入最小堆timers中,timers使用数组实现的一个最小堆,堆顶为离当前最近的一个timer。

timer定制完毕后就可以调用ev_run函数开始event loop了。在ev_run函数中,关于timer的代码流程大致如下:

int
ev_run (EV_P_ int flags)
{
  ....

  do
    {
    ....
/* 计算epoll等事件驱动机制的阻塞时间 */ {/* 堆顶取出ANHE,减去当前时间,赋值给waittime */
/* 调整waittime */ backend_poll (EV_A_ waittime); /* epoll_poll() */ }
....
/* queue pending timers and reschedule them */ /* 调整堆,取出所有超时的timer */ timers_reify (EV_A); /* relative timers called last */
/* 调用pendings数组中watcher的回调函数 */ EV_INVOKE_PENDING; } }

 

根据最小堆timers计算事件驱动机制的阻塞等待时间,阻塞返回后timers_reify函数记录所有超时的timer,最后由EV_INVOKE_PENDING执行这些timer对应的超时回调函数。在timers_reify函数中,如果timer是单次触发类型,那么会把该timer从最小堆中删除,如果timer是重复触发类型,那么会把该timer重新放入最小堆中,等待下次触发。

 

参考:

http://my.oschina.net/u/917596/blog/177300

 

Libev学习笔记4

标签:

原文地址:http://www.cnblogs.com/oyld/p/4512568.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!