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内 ...
随机推荐
- unity 随笔
转载 慕容小匹夫 从游戏脚本语言说起,剖析Mono所搭建的脚本基础 深入浅出聊优化:从Draw Calls到GC 谁偷了我的热更新?Mono,JIT,IOS JS or C ...
- 当点击回车键后form表单就可提交的实现
$('#myform').find('input').on('keyup',function(event){ if(event.keyCode == 13){ $('#myform').submit( ...
- 利用ant脚本 自动构建svn增量/全量 系统程序升级包【转】
引文:我们公司是做自己使用产品,迭代更新周期短,每次都花费较多时间和精力打包做增量更新,发现了一篇文章用于 自动构建svn增量/全量 系统程序升级包,收藏之,希望可以通过学习,更加简化我们的工作. 文 ...
- PowerDesigner 修改table背景色
Tools->Display Preferences(显示参数选择)->Format->Table->Modify->Fill->Fill color 出处:htt ...
- yii Nav:widget 配置参数encodeLabels
echo Nav::widget([ 'options' => ['class' => 'navbar-nav navbar-right'], 'encodeLabels' => f ...
- html页面嵌套---分享功能
1.使用原因 项目中用到了thymeleaf去渲染模板,但是我们这有一个分享的页面,分享出去的页面要加上与生成模板不一样的内容.因为重新再加一套模板又会引起内容的重复与资源浪费.这里就用到了JS的lo ...
- node+mysql简单注册
1前台文件 <!doctype html> <html> <head> <meta charset="UTF-8" /> <t ...
- python爬取股票信息
import requests from bs4 import BeautifulSoup import traceback import re def getHTMLText(url): try: ...
- 进制转换&数据类型(1)
一: 进制转换 在计算机中, 数据都是以0和1来表示的 进制: 进位制 十进制: 数字由0~9这10个数字来表示, 逢10进1位 0 1 2 3 4 5 6 7 8 9 10 二进制: 数字由0和1这 ...
- as3.0拼图
package com{ import flash.display.MovieClip; import flash.events.MouseEvent; import flash.geom.Point ...