linux内核中hlist_head和hlist_node结构解析
hlist_head和hlist_node用于散列表,分表表示列表头(数组中的一项)和列表头所在双向链表中的某项,两者结构如下:
|
1
2
3
|
struct hlist_head {
struct hlist_node *first;
};
|
|
1
2
3
|
struct hlist_node {
struct hlist_node *next, **pprev;
};
|
在内核中的普通双向链表基本上都是通过list_head实现的:
|
1
2
3
|
struct list_head {
struct list_head *next, *prev;
};
|
list_head很好理解,但是hlist_head和hlist_node为何要这样设计呢?
先看下hlist_head和hlist_node的示意图:

hash_table为散列表(数组),其中的元素类型为struct hlist_head。以hlist_head为链表头的链表,其中的节点hash值是相同的(也叫冲突)。first指针指向链表中的节点①,然后节点①的pprev指针指向hlist_head中的first,节点①的next指针指向节点②。以此类推。
hash_table的列表头仅存放一个指针,也就是first指针,指向的是对应链表的头结点,没有tail指针也就是指向链表尾节点的指针,这样的考虑是为了节省空间——尤其在hash bucket(数组size)很大的情况下可以节省一半的指针空间。
为什么pprev是一个指向指针的指针呢?按照这个设计,我们如果想要得到尾节点,必须遍历整个链表,可如果是一个指向节点的指针,那么头结点现在的pprev便可以直接指向尾节点,也就是list_head的做法。
对于散列表来说,一般发生冲突的情况并不多(除非hash设计出现了问题),所以一个链表中的元素数量比较有限,遍历的劣势基本可以忽略。
在删除链表头结点的时候,pprev这个设计无需判断删除的节点是否为头结点。如果是普通双向链表的设计,那么删除头结点之后,hlist_head中的first指针需要指向新的头结点。通过下面2个函数来加深理解:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
//添加节点到链表头
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
struct hlist_node *first = h->first;
n->next = first;//新节点的next指针指向原头结点
if (first)
first->pprev = &n->next;//原头结点的pprev指向新节点的next字段
h->first = n;//first指针指向新的节点(更换了头结点)
n->pprev = &h->first; //此时n是链表的头结点,将它的pprev指向list_head的first字段
}
//删除节点
static inline void __hlist_del(struct hlist_node *n)
{
struct hlist_node *next = n->next;
struct hlist_node **pprev = n->pprev;
*pprev = next; // pprev指向的是前一个节点的next指针,当该节点是头节点时指向 hlist_head的first,两种情况下不论该节点是一般的节点还是头结点都可以通过这个操作删除掉所需删除的节点。
if (next)
next->pprev = pprev;//使删除节点的后一个节点的pprev指向删除节点的前一个节点的next字段,节点成功删除。
}
|
因本人水平有限,若文章内容存在问题,恳请指出。允许转载,转载请在正文明显处注明原站地址以及原文地址,谢谢!
linux内核中hlist_head和hlist_node结构解析的更多相关文章
- Linux内核中的算法和数据结构
算法和数据结构纷繁复杂,但是对于Linux Kernel开发人员来说重点了解Linux内核中使用到的算法和数据结构很有必要. 在一个国外问答平台stackexchange.com的Theoretica ...
- Linux内核中namespace之PID namespace
前面看了LInux PCI设备初始化,看得有点晕,就转手整理下之前写的笔记,同时休息一下!!~(@^_^@)~ 这片文章是之前写的,其中参考了某些大牛们的博客!! PID框架的设计 一个框架的设计会考 ...
- Linux内核中的GPIO系统之(3):pin controller driver代码分析
一.前言 对于一个嵌入式软件工程师,我们的软件模块经常和硬件打交道,pin control subsystem也不例外,被它驱动的硬件叫做pin controller(一般ARM soc的datash ...
- Linux内核中流量控制
linux内核中提供了流量控制的相关处理功能,相关代码在net/sched目录下:而应用层上的控制是通过iproute2软件包中的tc来实现, tc和sched的关系就好象iptables和netfi ...
- 嵌入式C语言自我修养 01:Linux 内核中的GNU C语言语法扩展
1.1 Linux 内核驱动中的奇怪语法 大家在看一些 GNU 开源软件,或者阅读 Linux 内核.驱动源码时会发现,在 Linux 内核源码中,有大量的 C 程序看起来“怪怪的”.说它是C语言吧, ...
- Linux内核中的GPIO系统之(3):pin controller driver代码分析--devm_kzalloc使用【转】
转自:http://www.wowotech.net/linux_kenrel/pin-controller-driver.html 一.前言 对于一个嵌入式软件工程师,我们的软件模块经常和硬件打交道 ...
- 剖析linux内核中的宏---------container_of
#define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member) * __mptr = (ptr); ...
- Linux 内核中的 Device Mapper 机制
本文结合具体代码对 Linux 内核中的 device mapper 映射机制进行了介绍.Device mapper 是 Linux 2.6 内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机 ...
- 向linux内核中添加外部中断驱动模块
本文主要介绍外部中断驱动模块的编写,包括:1.linux模块的框架及混杂设备的注册.卸载.操作函数集.2.中断的申请及释放.3.等待队列的使用.4.工作队列的使用.5.定时器的使用.6.向linux内 ...
随机推荐
- windows下一分钟配置ngnix实现HLS m3u8点播
1. 下载 nginx-1.5.10 for windows 2. 修改配置文件nginx-1.5.10\conf\nginx.conf,增加以下行到最后一个"}"的前一行: lo ...
- python os模块的使用(转)
os模块包含普遍的操作系统功能. 注意:函数参数path是文件或目录的路径,filename是文件的路径,dirname是目录的路径,路径可以是相对路径,也可绝对路径 常见或重要的函数为加粗字体 os ...
- webpack 中使用 vue-router 注意
//render 会把el指定的容器中所有的内容都清空把#app也会去掉 都在c(app)其中的app组件中展示 所有router-link router-view要写在app这个组件里面 //A ...
- Lucene 全文检索引擎
Apache Lucene PS: 苦学一周全文检索,由原来的搜索小白,到初次涉猎,感觉每门技术都博大精深,其中精髓亦是不可一日而语.那小博猪就简单介绍一下这一周的学习历程, 仅供各位程序猿们参考,这 ...
- CSSの変数を使う
この文章はhttps://developer.mozilla.org/ja/docs/Web/CSS/Using_CSS_variablesを参考します. これは実験段階の機能です.この機能は複数のブ ...
- scrapy 是指user_agent
1.倒入random模块 2.在settings文件中添加useragent列表 MY_USER_AGENT = [ "Mozilla/4.0 (compatible; MSIE 6.0; ...
- java面试题:分布式
分布式分为分布式缓存(Redis).分布式锁(Redis或Zookeeper).分布式服务(Dubbo或SpringCloud).分布式服务协调(Zookeeper).分布式消息队列(Kafka.Ra ...
- cdh5.13.1 hadoop hdfs HA模式无法启动
经过观察日志发现,JN三个节点启动正常,只有NN节点启动时提示JN节点没有格式化 停止HDFS下面所有服务 先启动JN节点 然后启动一个NN节点,观察三个JN节点日志 发现其中一个节点的日志正常,没有 ...
- Windows配置Java环境
https://jingyan.baidu.com/article/84b4f56598d88b60f7da3272.html
- 二分 poj 3273
题目链接:https://vjudge.net/problem/POJ-3273 把n个连续的数字划分成m个连续的部分,每个部分都有一个部分和(这个部分所有值加起来),现在要使划分里最大的那个部分和最 ...