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数据结构分析

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

领域驱动设计学习成果分享

创建领域对象采用构造函数或者工厂,如果用工厂时需要依赖于领域服务或仓储,则通过构造函数注入到工厂; 一个聚合是由一些列相联的Entity和Value Object组成,一个聚合有一个聚合根,聚合根是E...
  • wutao322
  • wutao322
  • 2013年10月17日 16:37
  • 1028

浅谈设计模式的六大原则

一,单一职责原则:就一个类而言,应该仅有一个引起它变化的原因(就是实现类要责任单一) 英文--Single Responsibility Principle  简写:SRP 举个例子:    父类:A...
  • qq_28055429
  • qq_28055429
  • 2016年05月26日 21:48
  • 1570

【深度学习】中科院计算所:潘汀——深度学习框架设计中的关键技术及发展趋

潘汀,中科院计算所2017级博士生,导师山世光研究员。主要研究兴趣为目标检测技术与深度学习框架设计,目前独立开发与维护基于计算图的多重虚拟化深度学习框架Dragon。 导读 框架已经成为快...
  • np4rHI455vg29y2
  • np4rHI455vg29y2
  • 2017年11月13日 00:00
  • 624

linux内核哈希表hlist

Linux内核哈希表分析与应用 Author:tiger-john Time:2012-12-20 mail:jibo.tiger@gmail.com Blog:http://bl...
  • djinglan
  • djinglan
  • 2013年04月16日 10:26
  • 2466

深度学习框架-浅析深度学习框架设计中的关键技术

编者按:如果把深度学习比作一座城,框架则是这座城中的水路系统,而基于拓扑图的计算恰似城中水的流动,这种流动赋予了这座城以生命。一个优雅的框架在保证城市繁荣的同时,还能让这座城市散发出独特的魅力,使它保...
  • u012968002
  • u012968002
  • 2017年08月02日 12:45
  • 314

Java 8 API 设计经验浅析

任何写Java代码的人都是API设计师!无论编码者是否与他人共享代码,代码仍然被使用:要么其他人或他们自己使用,要么两者皆有。因此,对于所有的Java开发人员来说,了解良好API设计的基础很重要。 ...
  • lc0817
  • lc0817
  • 2016年12月03日 14:42
  • 309

“Ceph浅析”系列之四——Ceph的工作原理及流程

原文在 http://yizhaolingyan.net/?p=63, 感谢作者 @一棹凌烟         本文将对Ceph的工作原理和若干关键工作流程进行扼要介绍。如前所述,由于Ceph的...
  • scaleqiao
  • scaleqiao
  • 2015年06月08日 17:09
  • 1133

“Ceph浅析”系列之一——Ceph概况

最近正在学习ceph,本来也想自己写个ceph系列来跟踪记录自己的学习过程,但是因为作者 @一棹凌烟,之前关于ceph的系列文章写的太好,所以先把精华部分转过来做个备份。当然,随着自己的学习的深入,本...
  • scaleqiao
  • scaleqiao
  • 2015年06月08日 16:49
  • 985

“Ceph浅析”系列

开源技术专家章宇同学(@一棹凌烟)在C3沙龙分享过Ceph之后,最近来了劲头,一口气写了一系列《Ceph浅析》的博文,共8篇: “Ceph浅析”系列之一——前言 “Ceph浅析”系列之二——Ceph概...
  • qq_24916117
  • qq_24916117
  • 2015年12月30日 18:08
  • 586
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:hlist_head / hlist_node 设计浅析
举报原因:
原因补充:

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