freeBSD TAILQ队列的理解
来源:互联网 发布:mac如何截屏快捷键 编辑:程序博客网 时间:2024/06/08 06:50
from http://www.cnblogs.com/UnGeek/archive/2013/03/29/2989325.html
在看libevent源码中TAILQ的时候发现了一些让我迷惑的地方,就是里面的双端队列以及链表中节点的next与prev指针,它的设计与我们一般的链表以及linux内核的list完全不一样,因为里面的prev根本不是指向前一个节点,而是指向前一个节点的next元素的地址:
#define TAILQ_HEAD(name, type) \
struct
name { \
struct
type *tqh_first;
/* first element */
\
struct
type **tqh_last;
/* addr of last next element */
\
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct
{ \
struct
type *tqe_next;
/* next element */
\
struct
type **tqe_prev;
/* address of previous next element */
\
}
还有一个令人迷惑的地方是下面的两个macros:
#define TAILQ_LAST(head, headname) \
(*(((
struct
headname *)((head)->tqh_last))->tqh_last))
/* XXX */
#define TAILQ_PREV(elm, headname, field) \
(*(((
struct
headname *)((elm)->field.tqe_prev))->tqh_last))
首先我们定义两个用于分析的实例
struct user{
int i;
TAILQ_ENTRY(user) entry
};
TAILQ_HEAD(head,user) tq
head * ptq = & tq
为什么要强制转换问headname*呢,先将TAILQ_LASR进行分解来说明,TAILQ_PREV类似:
@1 (head)->tqh_last
@2 ( (struct headname *) (@1) )
@3 ( *((@2)->tqh_last) )
我们要获得自己定义的tq的最后一个节点的地址应这样使用
TAILQ_LAST(ptq, head)
由@1 我们得到的是ptq->tqh_last,即最后一个节点TAILQ_ENTRY(type)的struct type *tqe_next;元素的地址,这时候我们只要获得struct type **tqh_last的值就能得到该节点的地址值,就是last节点(注意不是前一个),现在如何获得struct type **tqh_last是关键所在。仔细观察我们发现TAILQ_ENTRY与TAILQ_HEAD的内存布局实际上是一样的,都是对应两个元素共八个字节,现在有两种方法获得struct type **tqh_last。
1.struct type *tqe_next的地址值直接加4
2.将struct type *tqe_next强制转换成head,也就是源代码中的方法
现在主要分析第二中解决方案,@2是一个head* 指针,通过@3之后我们实际得到的是前一个节点的struct type *tqe_next地址的解引用,就是last节点的地址,这里有点迷惑((@2)->tqh_last)实际对应的是TAILQ_ENTRY节点的struct type **tqe_prev元素,它指向的是前一个节点的struct type *tqe_next地址,这样一来我们便能得到最好一个节点的地址了,TAILQ_PREV使用的方法也是一样的。至于为什么使用2方法不用1方法,我是这样理解的,使用1方法需要进行加法运算,会消耗CPU周期,这对于网络应用与内核是很关键的,而且通过使用方法2可以易于移植,因为当将内核移植到64位机器的时候方法1肯能就会产生错误。
也许上面的讲解一时无法理解,但是只要记住一点的就是TAILQ_ENTRY与TAILQ_HEAD的内存布局是一样的,为什么TAILQ_LAST和TAILQ_PREV中不将(head)->tqh_last)转换为TAILQ_HEAD而不是转换为TAILQ_ENTRY是因为TAILQ_ENTRY这个结构体是直接定义在你用户定义的结构体中,无法获取他的类型来进行转换
- freeBSD TAILQ队列的理解
- 关于libevent与FreeBSD内核中TAILQ队列的理解
- 深入理解FreeBSD中的TAILQ
- 深入理解FreeBSD中的TAILQ
- 深入理解TAILQ队列
- 深入理解TAILQ队列
- 深入理解TAILQ队列
- 深入理解TAILQ队列
- 深入理解TAILQ队列
- 深入理解TAILQ队列
- 深入理解FreeBSD中的TAILQ ------good
- LINUX下的TAILQ队列
- queue.h之tailq.h尾队列理解使用
- 深入理解TAILQ队列(转自http://blog.csdn.net/hunanchenxingyu/article/details/8648794)
- tailq
- Linux queue.h之TAILQ队列分析!
- C语言之尾队列tailq
- C语言之尾队列tailq
- windows 网络问题
- Struts2学习笔记一(运行流程及自定义类型转换)
- java生成二维码使用QRCode和ZXing两种方式
- 简单的侧滑菜单实现
- android多线程下载
- freeBSD TAILQ队列的理解
- 支付宝可以休矣,淘宝才是阿里社交的正确选择
- UVA 10163 Storage Keepers
- fmt包的占位符
- adapter实例
- mongodb分片+集群
- 遍历字符串 返回字符重复出现的次数
- 【NOIP 2011】 选择客栈
- 深入理解FreeBSD中的TAILQ ------good