本文主要研究libevent中用来存储事件的两个结构体。

尾队列

具体定义位于queue.h中。

#define    TAILQ_HEAD(name, type)                        \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
} #define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
} #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_INIT(head) do { \
TAILQ_FIRST((head)) = NULL; \
(head)->tqh_last = &TAILQ_FIRST((head)); \
} while () #define TAILQ_INSERT_TAIL(head, elm, field) do { \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
} while () #define TAILQ_INSERT_HEAD(head, elm, field) do { \
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
TAILQ_FIRST((head))->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
TAILQ_FIRST((head)) = (elm); \
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
} while () #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
TAILQ_NEXT((elm), field)->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else { \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
} \
TAILQ_NEXT((listelm), field) = (elm); \
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
} while () #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
TAILQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
} while () #define TAILQ_REMOVE(head, elm, field) do { \
if ((TAILQ_NEXT((elm), field)) != NULL) \
TAILQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \
else { \
(head)->tqh_last = (elm)->field.tqe_prev; \
} \
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
} while ()

从定义可以看出,尾队列是一个双向链表,具体表现为:

一个小DEMO:

#include <stdio.h>
#include <stdlib.h>
#include <sys/queue.h> #define LIST_SIZE 5 // 声明头结点
TAILQ_HEAD(event_list, event);
// 声明元素结点
struct event {
int value;
TAILQ_ENTRY(event) field;
}; int main(int argc, char **argv) {
event_list *list = (event_list*)malloc(sizeof(event_list));
TAILQ_INIT(list); event *item;
for (int i = ; i < LIST_SIZE; i++) {
item = (event*)malloc(sizeof(event));
item->value = i;
item->field.tqe_next = NULL;
item->field.tqe_prev = NULL; TAILQ_INSERT_TAIL(list, item, field);
} printf("当前list: ");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
printf("%d ", item->value);
}
printf("\n"); event **test = list->tqh_first->field.tqe_prev;
if (test == &list->tqh_first) {
printf("guess right\n");
} printf("尾部插入结点: 10\n");
item = (event*)malloc(sizeof(event));
item->value = ;
item->field.tqe_next = NULL;
item->field.tqe_prev = NULL;
TAILQ_INSERT_TAIL(list, item, field); printf("当前list: ");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
printf("%d ", item->value);
}
printf("\n"); printf("头部插入结点: 20\n");
item = (event*)malloc(sizeof(event));
item->value = ;
item->field.tqe_next = NULL;
item->field.tqe_prev = NULL;
TAILQ_INSERT_HEAD(list, item, field); printf("当前list: ");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
printf("%d ", item->value);
}
printf("\n"); printf("在值为3的结点之后插入结点: 30\n");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
if (item->value == ) {
event *new_item = (event*)malloc(sizeof(event));
new_item->value = ;
new_item->field.tqe_next = NULL;
new_item->field.tqe_prev = NULL;
TAILQ_INSERT_AFTER(list, item, new_item, field);
}
} printf("当前list: ");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
printf("%d ", item->value);
}
printf("\n"); printf("在值为1的结点之前插入结点: 40\n");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
if (item->value == ) {
event *new_item = (event*)malloc(sizeof(event));
new_item->value = ;
new_item->field.tqe_next = NULL;
new_item->field.tqe_prev = NULL;
TAILQ_INSERT_BEFORE(item, new_item, field);
}
} printf("当前list: ");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
printf("%d ", item->value);
}
printf("\n"); printf("删除值为3的结点\n");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
if (item->value == ) {
TAILQ_REMOVE(list, item, field);
}
} printf("当前list: ");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
printf("%d ", item->value);
}
printf("\n"); printf("Done\n");
}

最小堆

typedef struct min_heap
{
struct event** p; // 指向event*指针数组
unsigned n, a;  // a表示堆的大小,n表示堆中元素个数
} min_heap_t;
void min_heap_ctor(min_heap_t* s) { s->p = ; s->n = ; s->a = ; }
void min_heap_elem_init(struct event* e) { e->ev_timeout_pos.min_heap_idx = -; }
unsigned min_heap_size(min_heap_t* s) { return s->n; }

参考资料:

do {...} while (0) 的用途汇总(欢迎补充)

libevent(二)尾队列 && 最小堆的更多相关文章

  1. libevent中最小堆实现算法解析

    libevent,一个非常好的c的网络库,最近开始学习并分析下,做个记录.源码选用的1.4版本.因为感觉这版的代码比较精简,也没有太多宏定义,个人感觉适合学习原理. 从哪里开始呢,我选择从一些最简单的 ...

  2. Libevent源码分析(一):最小堆

    Libevent中的timeout事件是使用最小堆来管理维护的.代码位于<minheap-internal.h>. 看函数命名和代码风格应该是一个C++程序员,函数名都挺好懂的,只是下面这 ...

  3. ZOJ 2724 Windows Message Queue (优先级队列,水题,自己动手写了个最小堆)

    #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm& ...

  4. java实现最小堆

    1.堆:通常通过二叉堆,实为二叉树的一种,分为最小堆和最大堆,具有以下性质: 任意节点小于它的所有后裔,最小元在堆的根上. 堆总是一棵完全树 将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小 ...

  5. 优先队列——二项队列(binominal queue)

    [0]README 0.1) 本文文字描述部分转自 数据结构与算法分析, 旨在理解 优先队列——二项队列(binominal queue) 的基础知识: 0.2) 本文核心的剖析思路均为原创(inse ...

  6. Python3实现最小堆建堆算法

    今天看Python CookBook中关于“求list中最大(最小)的N个元素”的内容,介绍了直接使用python的heapq模块的nlargest和nsmallest函数的解决方式,记得学习数据结构 ...

  7. 【数据结构】通用的最小堆(最大堆)D-ary Heap

    听说有一种最小(大)堆,不限于是完全二叉树,而是完全D叉树,名为D-ary Heap(http://en.wikipedia.org/wiki/D-ary_heap).D可以是1,2,3,4,100, ...

  8. My集合框架第五弹 最小堆

    二叉堆(以最小堆为例),其具有结构性质和堆序性质结构性质: 堆是一棵完全的二叉树,一颗高为h的完全二叉树有2^h到2^h-1个节点,高度为log N            而且该结构可以很容易的使用数 ...

  9. 最小堆实现优先队列:Python实现

    最小堆实现优先队列:Python实现 堆是一种数据结构,因为Heapsort而被提出.除了堆排序,“堆”这种数据结构还可以用于优先队列的实现. 堆首先是一个完全二叉树:它除了最底层之外,树的每一层的都 ...

随机推荐

  1. go1.13errors的用法

    go1.13errors的用法 前言 基本用法 fmt.Errorf Unwrap errors.Is As 扩展 参考 go1.13errors的用法 前言 go 1.13发布了error的一些新的 ...

  2. Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十)之Inner Classes

    The inner class is a valuable feature because it allows you to group classes that logically belong t ...

  3. Kafka 2.5.0发布——弃用对Scala2.11的支持

    近日Kafka发布了最新版本 2.5.0,增加了很多新功能: 下载地址:https://kafka.apache.org/downloads#2.5.0 对TLS 1.3的支持(默认为1.2) 引入用 ...

  4. Application.Exit

    Application.Exit:通知winform消息循环退出.Environment.Exit:终止当前进程,返回exitcode给操作系统 Application.Exit会在所有前台线程退出后 ...

  5. VMware15 安装Mac 10.14系统/苹果系统

    安装环境 Windows专业版 VMware Workstation Pro 15 所需资源 VMware Workstation Pro 15.0.0 Build 10134415 官网下载地址:h ...

  6. [YII2] 增删改查2

    一.新增 使用model::save()操作进行新增数据 $user= new User; $user->username =$username; $user->password =$pa ...

  7. 必须先理解的RocketMQ入门手册,才能再次深入解读

    RocketMQ入门手册 RocketMQ是一个分布式.队列模型的开源消息中间件,前身是MetaQ,是阿里研发的一个队列模型的消息中间件,后开源给apache基金会成为了apache的顶级开源项目,具 ...

  8. 8、Flink Table API & Flink Sql API

    一.概述 上图是flink的分层模型,Table API 和 SQL 处于最顶端,是 Flink 提供的高级 API 操作.Flink SQL 是 Flink 实时计算为简化计算模型,降低用户使用实时 ...

  9. javascript-文件File转换成base64格式

    不能直接访问用户计算机中的文件,一直都是Web应用开发中的一大障碍.2000年以前,处理文件的唯一方式就是在表单中加入<input type="file">字段,仅此而 ...

  10. 2019-2020-1 20199308《Linux内核原理与分析》第八周作业

    <Linux内核分析> 第七章 可执行程序工作原理 7.1 知识点 1.目标文件:编译器生成的文件,"目标"指平台,它决定了编译器使用的机器指令集. 2.目标文件格式: ...