hlist_head / hlist_node 设计浅析

原创 2015年11月18日 10:44:45

Linux内核提供的数据结构里,除了常见的list,还有他的另一个孪生兄弟——hlist(由struct hlist_headstruct hlist_node构成)。hlist结构如下:

struct hlist_head {
    struct hlist_node *first;
};

struct hlist_node {
    struct hlist_node *next, **pprev;
};


就像hlist名字中h所预示的那样,他主要用于hash_table。在典型的hash_table,我们用链表处理散列冲突(colision)。此时,我们都是从数组的某一个位桶(slot)出发,沿着链表搜索,从而获取目标元素。

在这种情况下,很难想象会有这么一种需求——我们需要重新回到散列数组的位桶中,也就是说,我们不需要一个用于指向数组元素的指针。

hlist discription

这样,我们就省下了一个指针!或者说,省下了n * sizeof(void *)个字节(这里的n是散列数组的长度)。以Linux2.6.11中的pid_hash[]、32位系统为例,共有4张表,每张表2048个slot,省下了

2221125=218bits=215Bytes=32KB


但故事并没有就此结束,hlist还有个让人乍看之下颇为费解的地方——hlist_node.pprev。这里,他不是简单地使用struct hlist_node *指向前节点(previous node),而像是没事找事似的,是一个struct hlist_node **指针。至于答案,还是得到源代码中去搜寻一番。为了使文章不至于充斥过多的代码,这里仅仅以添加元素为例,讲讲个中缘由。

static inline void hlist_add_head(struct hlist_node *n,
                                  struct hlist_head *h)
{
    struct hlist_node *first = h->first;
    n->next = first;
    if (first)
        first->pprev = &n->next;
    h->first = n;
    n->pprev = &h->first;
}


想象一下,当我们插入一个节点时,注意最后一个语句n->pprev = &h->first,这里,我们把h->first的地址赋给了待插入节点的pprev!这里就是最大的问题所在了。hlist_node组成一个双向链表,可是他们的头节点却叫hlist_head,这叫hlist_node如何用一个struct hlist_node *类型的指针去指向头节点呢?

退而求其次,hlist_head中有一个first域(field),用于执行整个链的第一个节点,而这个节点,逻辑上恰恰充当了head的next域。如此一来,当我们使用struct hlist_node **pprev指向前一个节点的next时(在第一个节点眼里,head也是他的前驱),在整个链表中(包括头节点),我们便取得了处理的一致性,便于节点的插入删除(这也是使用双向链表的原因)。

至于说pprev是指向前一个节点的next的指针,也可以在上面的函数中找到根据:

if (first)
    first->pprev = &n->next;

这里,first不等于0,表示链表中已有元素,此时将旧的第一个元素(这里的first)的pprev指向新插入元素的next

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Linux内核 hlist_head/hlist_node结构解析

int fz_divisor; 表示散列表fz_hash的容量,以及散列表桶的数目。 内核中的定义: struct hlist_head {     struct hlist_node *firs...

内核数据结构:hlist_head

内核数据结构:hlist_head 分类: Linux内核 2011-05-16 20:58 391人阅读 评论(1) 收藏 举报 内核中,使用list_head作为链表...

Kernel base Series(3)-----hlist_nulls_head

分类: 原文地址:Kernel base Series(3)-----hlist_nulls_head 作者:mtloveft 声明:本文为原创 #####请转贴时保留以...

在用户空间编程使用linux内核链表list,hlist宏定义和操作

在用户空间编程使用linux内核链表list,hlist宏定义和操作. linux内核中的list_head和hlist_head/hlist_node是将数据结构串起来成为链表的两个重要链表构造工...

linux内核之hlist哈希链表的应用---C语言代码实现(内核态)

本文是继linux内核之链表操作解析 之后对linux内核中链表和哈希链表的操作宏以及操作函数的一个应用; 第一步:是定义数据类型,主要是哈希链表,因为用的是拉链法(也叫数组链表)处理碰撞,所以也可以...

hlist

来自:http://blog.csdn.net/zhanglei4214/article/details/6767288 在Linux内核中,hlist(哈希链表)使用非常广泛。本文将对其数...

Go语言移植Linux内核数据结构hlist

hlist(哈希链表)可以通过相应的Hash算法,迅速找到相关的链表Head及节点. 在有些应用场景,比Go标准库提供的list(一种常见的双向链表)更合适。     依照list.h中的源码,我实现...

hlist哈希链表的实现--C代码实现程序

hlist 哈希链表的实现--C代码实现程序(用户态)。在前面已经对哈希链表进行了全面的讲解,包括哈希链表的定义,哈希链表的哈希函数以及怎么处理哈希碰撞问题。如果不是很熟悉哈希链表的一些的概念的可以先...

Linux内核hlist数据结构分析

在内核编程中哈希链表hlist使用非常多,比如在openvswitch中流表的存储中就使用了(见[1])。hlist的表头仅有一个指向首节点的指针,而没有指向尾节点的指针,这样在有很多个buckets...

内核hlist链表

出处:http://hi.baidu.com/kwokwing0011/blog/item/cfde8337e575950191ef3912.html 内核中的定义: struct h...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)