您的位置:首页 > 产品设计 > UI/UE

TailQueue详解

2015-10-29 10:24 651 查看
TailQueue详解

本文详细解释Libevent中TailQueue数据结构及使用方法。

采用的基础数据结构如下所示:该数据结构包含2个业务字段,设备编号devId和设备名称name。

struct AlarmInfo

{

//业务数据

int devId;

const char name[32];

}

如果要采用TailQueue进行改结构体保存,必须在该数据结构中增加字段用于建立链表之用,如下所示:

struct AlarmInfo

{

//业务数据

int devId;

const char name[32];

TAILQ_ENTRY(AlarmInfo) TQueueField;

}

TAILQ_ENTRY(AlarmInfo)TQueueField;是一个宏定义,展开后该数据结构如下:

struct AlarmInfo

{

//业务数据

int devId;

const char name[32];

Struct

{

struct AlarmInfo *tqe_next;

struct AlarmInfo **tqe_prev;

} TQueueField;

}

tqe_next指向下一个要素的地址;

tqe_prev指向前一个要素的next指针的地址。

这样,基本的数据结构就定义完毕。

但是,还必须有其他的辅助手段,才能实现数据的存取。

首先,定义一个列表头,其宏定义如下:

#define TAILQ_HEAD(name, type)

struct name

{

/* first element */

Struct type *tqh_first;

/* addr of last next element */

Struct type **tqh_last;

}

对于本文中的AlarmInfo数据需要通过如下语句定义一个新的结构体: TAILQ_HEAD(AlarmInfoTaileQueue,AlarmInfo);

该宏定义展开后如下图所示:

struct AlarmInfoTaileQueue

{

Struct AlarmInfo *tqh_first;

Struct AlarmInfo **tqh_last;

};

然后就可以用该结构体定义一个实际的结构体实例,用于保存改队列的头节点。

struct AlarmInfoTaileQueue alarmTQHead;

在使用该头节点前,需要对其进行初始化:

TAILQ_INIT(&alarmTQHead);

其宏定义如下:

#define TAILQ_INIT(head) do {\

(head)->tqh_first = NULL; \

(Head)->tqh_last = &(head)->tqh_first;\

} while (0)

主要作用就是将头指针(tqh_first)初始化为NULL,将尾指针(指向指针的指针)指向头指针(tqh_first)的地址。

接下来,就可以通过该头节点对该队列进行操作了。

//增加要素进入队列

AlarmInfoalr;

for(i=0;i<10;i++)

{

//创建该结构体实例。

alr =NewAlarmInfo();

if(NULL== alr){return;}

alr -> devId =i;

sprintf(tem,"jiayp%d",i+1);

strcpy(alr->name,tem);

TAILQ_INSERT_TAIL(&alarmTQHead,alr,TQueueField);

}

TAILQ_INSERT_TAIL宏定义如下:

#define TAILQ_INSERT_TAIL(head, elm, field) do {\

(elm)->field.tqe_next = NULL;\

(elm)->field.tqe_prev = (head)->tqh_last;\

*(head)->tqh_last = (elm);\

(head)->tqh_last = &(elm)->field.tqe_next;\

} while (0

该宏定义实现功能如下图:

调用TAILQ_INIT(&alarmTQHead)后如下图所示:



第一次调用TAILQ_INSERT_TAIL(&alarmTQHead,alr,TQueueField);后如下图所示:

首先,将AlarmInfo节点下TequeueField的tqe_next的指针设置为NULL;

然后,将AlarmInfo节点下TequeueField的tqe_prev(指向指针的指针)设置到alarmTQHead的Tqh_first(因为原来尾指针(指向指针的指针)就是指向头指针的地址);

然后,将尾指针(此时改指针仍然指向头指针的地址),所以是将头指针指向实际的数据对象(AlarmInfo)地址;

最后,将尾指针,指向新对象的teq_next指针的地址。



第二次调用TAILQ_INSERT_TAIL(&alarmTQHead,alr,TQueueField);后如下图所示:



这样就形成了一个链表,该链表的alarmTQHead节点,分别指向链表的第一和最后一个节点。

下面看一下链表的遍历过程:

static void OutputAll(){

struct AlarmInfo*alr;

TAILQ_FOREACH (alr,& alarmTQHead,TQueueField)

{

printf(alr->name);

}

}

TAILQ_FOREACH也是一个宏定义:

#define TAILQ_FOREACH(var, head, field)\

for((var) = AILQ_FIRST(head);\

(var) != TAILQ_END(head);\

(var) = TAILQ_NEXT(var, field))

代码展开后如下所示:

static void OutputAll()

{

struct AlarmInfo *alr;

for((var) = alarmTQHead ->tqh_first;(var) != NULL; (var)= var->TQueueField. tqe_next)

{

printf(alr->name);

}

}

该代码简单,不做详细说明。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: