libevent源码浅析(二):libevent的定时器的实现

在libevent中定时器的实现是通过基于最小堆的优先级队列来实现的。

对于这两个数据结构比较陌生的可以去翻算法导论的6.5节。

主要的源码都在min_heap.c中。

我们先来看主要的数据结构:

typedef struct min_heap
{
  struct event** p;
  unsigned n, a;
} min_heap_t;

在这个数据结构中 p也就是整个优先级队列,而这个优先级队列的每个节点都是一个struct *event.n表示这个队列的元素个数。a表示这个队列的大小.

接下来来看几个主要的方法:

min_heap_reserve调整队列的大小。

int min_heap_reserve(min_heap_t* s, unsigned n)
{
  if(s->a < n)
  {
    struct event** p;
///这里可以看到当需要扩大队列的空间时,每次都是以8的倍数进行扩展
    unsigned a = s->a ? s->a * 2 : 8;
    if(a < n)
      a = n;
///扩大队列的空间
    if(!(p = (struct event**)realloc(s->p, a * sizeof *p)))
      return -1;
    s->p = p;
    s->a = a;
  }
  return 0;
}

min_heap_shift_up_ 插入一个定时器到当前队列:

void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e)
{
 
///首先计算当前插入点的元素的父节点。
  unsigned parent = (hole_index - 1) / 2;
///循环处理定时器的位置,首先比较当前的定时器与他的父节点的定时器,如果大于父节点的定时器,则直接跳过循环然后将定时器加入队列。如果大与父节点的定时器则交换两个节点的值,然后这里还有个需要注意的地方就是min_heap_idx这个数据,它表示当前event对象也就是定时器对象在定时器队列的索引值。
  while(hole_index && min_heap_elem_greater(s->p[parent], e))
  {
    (s->p[hole_index] = s->p[parent])->min_heap_idx = hole_index;
    hole_index = parent;
    parent = (hole_index - 1) / 2;
  }
///得到定时器应插入的位置hole_index.
  (s->p[hole_index] = e)->min_heap_idx = hole_index;
}

min_heap_shift_down_ 取出当前的最短时间的定时器,其实也就是root节点,然后平衡此最小堆。

void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e)
{
///得到当前节点的右孩子。每次取出root节点之后,传递最后一个元素到root节点,然后平衡此最小堆。
  unsigned min_child = 2 * (hole_index + 1);
  while(min_child <= s->n)
 {
    min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]);
    if(!(min_heap_elem_greater(e, s->p[min_child])))
      break;
    (s->p[hole_index] = s->p[min_child])->min_heap_idx = hole_index;
    hole_index = min_child;
    min_child = 2 * (hole_index + 1);
 }
  min_heap_shift_up_(s, hole_index, e);
}

PS:其实只要对最小堆和优先级队列了解的话,这个定时器的实现很简单的说。。不过libevent的算法实现有些丑陋罢了。。

时间: 2024-10-26 23:19:11

libevent源码浅析(二):libevent的定时器的实现的相关文章

libevent源码浅析(四)

最近刚刚一个项目自己用libevent,因此这几天又把libevent的代码拿出来翻了下,当初看的时候有些似是而非的东西,这次是基本没有了.这篇也算是前面几篇libevent的blog的补充了. struct event_base { const struct eventop *evsel; void *evbase; int event_count; /* counts number of total events */ int event_count_active; /* counts nu

libevent源码浅析(一)

这里分析的是libevent-1.4.9. PS:前面还看了libev的源代码,妈的,那代码写的太猥亵了,相比较libevent代码写的好多了.. 首先来看一下最主要的几个数据结构: eventop结构体是所有事件驱动模型的基类.所有的io复用类型都会实现此结构体里各种方法. struct eventop { const char *name; ///<事件驱动名称 void *(*init)(struct event_base *); //<初始化 int (*add)(void *, st

libevent源码浅析(三):libevent的信号的处理

在libevent中通过使用socketpair建立一对流管道,也就是全双工管道,来将信号事件与句柄事件统一起来. 先来看数据结构: struct evsignal_info { struct event ev_signal; ///<所属的event int ev_signal_pair[2]; ///<创建的流管道 int ev_signal_added; ///<信号是否已被加入到event中的标记. volatile sig_atomic_t evsignal_caught; /

C1000K之Libevent源码分析

 简介 说到异步IO,高并发之类的名词, 可能很多人第一反应就是 select, poll, epoll, kqueue 之类的底层代码库. 但是其实除非你要写一个 Nginx 性能级别的服务器, 否则直接使用 epoll 之类的还是太过底层, 诸多不便,要榨干整个异步编程的高并发性能还需要开发很多相关组件, 而 Libevent 就是作为更好用的高性能异步编程网络库而生, 他帮你包装了各种 buffer 和 event, 甚至也提供了更加高层的 http 和 rpc 等接口, 可以让你脱离

Android源码浅析(二)——Ubuntu Root,Git,VMware Tools,安装输入法,主题美化,Dock,安装JDK和配置环境

Android源码浅析(二)--Ubuntu Root,Git,VMware Tools,安装输入法,主题美化,Dock,安装JDK和配置环境 接着上篇,上片主要是介绍了一些安装工具的小知识点Android源码浅析(一)--VMware Workstation Pro和Ubuntu Kylin 16.04 LTS安装配置,其实Ubuntu Kylin 16.04 LTS也只是为了体验,我们为了追求稳定,还是使用了Ubuntu14.04 这里提供一个国内镜像的下载链接,可以用迅雷,下载下来之后后缀

我对java String的理解 及 源码浅析

一.char说起到String 这也是自己第二次回过头来啃java基础书,小生自认为愚昧无知.如果大神有好的教育,可以评论私信.以下都是我的看法: 为什么说char 呢,我这里先卖个关子.在java中,char是用unicode编码的,占16位(2字节).从ansi编码(1字节)到unicode编码(2字 节).Java中使用Unicode的原因是,Java的Applet(网页)运行,Unicode里面包含最多最广比如:中 文,English,Spanish,German, French等.因此

Android源码浅析(一)——VMware Workstation Pro和Ubuntu Kylin 16.04 LTS安装配置

Android源码浅析(一)--VMware Workstation Pro和Ubuntu Kylin 16.04 LTS安装配置 最近地方工作,就是接触源码的东西了,所以好东西还是要分享,系列开了这么多,完结 的也没几个,主要还是自己覆盖的太广了,却又不精通,嘿嘿,工作需要,所以写下了本篇博客 一.VMware 12 我选择的虚拟机试VMware,挺好用的感觉,下载VMware就不说了,善用搜索键嘛,这里我提供一个我现在在用的 下载地址:链接:http://pan.baidu.com/s/1k

【深入浅出jQuery】源码浅析2--奇技淫巧

最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐进增强)优雅的处理能力以及 Ajax 等方面周到而强大的定制功能无不令人惊叹. 另外,阅读源码让我接触到了大量底层的知识.对原生JS .框架设计.代码优化有了全新的认识,接下来将会写一系列关于 jQuery 解析的文章. 我在 github 上关于 jQuery 源码的全文注解,感兴趣的可以围观一下

Android源码浅析(三)——Android AOSP 5.1.1源码的同步sync和编译make,搭建Samba服务器进行更便捷的烧录刷机

Android源码浅析(三)--Android AOSP 5.1.1源码的同步sync和编译make,搭建Samba服务器进行更便捷的烧录刷机 最近比较忙,而且又要维护自己的博客,视频和公众号,也就没仔细的梳理源码的入门逻辑,今天也就来讲一个源码的玩法,各位看官,一起学习学习! 看本篇博客之前,先看下我的前面两篇 Android源码浅析(一)--VMware Workstation Pro和Ubuntu Kylin 16.04 LTS安装配置 Android源码浅析(二)--Ubuntu Roo