Linux内核中的通用双向循环链表
开发中接触Linux越来越多,休息放松之余,免不了翻看翻看神秘的Linux的内核。看到双向链表时,觉得挺有意思的,此文记下。
作为众多基础数据结构中的一员,双向循环链表在各种“教科书”中的实现是相当的标准和一致的。
大概就是下面这个样子:
typedef struct node_tag{
//T data;
struct node_tag *prev;
struct node_tag *next;
}node;
当你需要某种类型的链表时,把数据成员之类的往节点里塞就是了。比如菜谱链表,里面就可以有宫爆鸡丁,酸辣粉,地三鲜,水煮鱼,麻辣鸡翅。。。
嗯,当你需要另外一种链表时,接着如法炮制,只要功夫深,几十上百也不是问题。有一部分人善于解决这类问题,它们叫做CP程序员(Copy-Paste),
不要问我为什么知道。C++模板在这点上能实现通用特性,但不在本次内容之列了。
有着极客精神的Linux,在内核中肯定不会像上面这么做的。内核中有大量的数据结构需要使用双向链表,诸如进程、模块、文件。
难道要人去维护各种类型的双向链表?而且还是不能复用的链表。我想没多少人愿意把时间花在这种事情上吧。维护一种通用的不就好了。
链表节点,作为一个“连接件”,最本质的内容就是把一些对象链接起来,至于对象内部存储的数据,是可以不用知道的。
在include/linux/list.h文件中,就有使用这样的一个"连接件“:
struct list_head {
struct list_head *next, *prev;
};
和node_tag相比,少了数据部分。
list_head作为独立变量时,充当的是链表头的角色;如果作为结构体成员时,则是“连接件”的角色。
在这样的实现方式下,要获得某种类型的链表,只需在宿主结构中声明一个list_head成员,还可以任意的取名;
关键是,链表操作只需以list_head为对象进行实现;剩下唯一的问题是,在遍历链表时,该如何获取宿主结构的首地址?
毕竟链表是用来装内容用的。这里利用编译器的一个小技巧就可以算出地址偏移
#define offsetof(s,m) (size_t)&(((s *)0)->m)
有了list_head相对宿主结构首地址的偏移,和自身地址来个加减就可以得到宿主的首地址,接下该怎么操作就怎么操作了。
个人觉得这里面有面向对象的意思。抽取出共同的“连接件” list_head,链表操作也以list_head为对象进行设计,
除了要具体访问操作宿主结构之外,全部都是共性的东西。
Linux内核中的通用双向循环链表的更多相关文章
- C语言通用双向循环链表操作函数集
说明 相比Linux内核链表宿主结构可有多个链表结构的优点,本函数集侧重封装性和易用性,而灵活性和效率有所降低. 可基于该函数集方便地构造栈或队列集. 本函数集暂未考虑并发保护. 一 ...
- Linux内核中的算法和数据结构
算法和数据结构纷繁复杂,但是对于Linux Kernel开发人员来说重点了解Linux内核中使用到的算法和数据结构很有必要. 在一个国外问答平台stackexchange.com的Theoretica ...
- linux内核中链表代码分析---list.h头文件分析(一)【转】
转自:http://blog.chinaunix.net/uid-30254565-id-5637596.html linux内核中链表代码分析---list.h头文件分析(一) 16年2月27日17 ...
- Linux内核中的GPIO系统之(3):pin controller driver代码分析
一.前言 对于一个嵌入式软件工程师,我们的软件模块经常和硬件打交道,pin control subsystem也不例外,被它驱动的硬件叫做pin controller(一般ARM soc的datash ...
- [翻译] Linux 内核中的位数组和位操作
目录 Linux 内核里的数据结构 原文链接与说明 Linux 内核中的位数组和位操作 位数组声明 体系结构特定的位操作 通用位操作 链接 Linux 内核里的数据结构 原文链接与说明 https:/ ...
- Linux内核中常用的数据结构和算法(转)
知乎链接:https://zhuanlan.zhihu.com/p/58087261 Linux内核代码中广泛使用了数据结构和算法,其中最常用的两个是链表和红黑树. 链表 Linux内核代码大量使用了 ...
- Linux内核中的软中断、tasklet和工作队列具体解释
[TOC] 本文基于Linux2.6.32内核版本号. 引言 软中断.tasklet和工作队列并非Linux内核中一直存在的机制,而是由更早版本号的内核中的"下半部"(bottom ...
- linux内核中socket的创建过程源码分析(总结性质)
在漫长地分析完socket的创建源码后,发现一片浆糊,所以特此总结,我的博客中同时有另外一篇详细的源码分析,内核版本为3.9,建议在阅读本文后若还有兴趣再去看另外一篇博文.绝对不要单独看另外一篇. 一 ...
- Linux内核中的GPIO系统之(3):pin controller driver代码分析--devm_kzalloc使用【转】
转自:http://www.wowotech.net/linux_kenrel/pin-controller-driver.html 一.前言 对于一个嵌入式软件工程师,我们的软件模块经常和硬件打交道 ...
随机推荐
- 漂亮的自制java验证码
网上有很多开源的验证码插件,例如jcaptcha,kaptcha等等...这些都不错,不过感觉用起来不太舒服,最后还是网上找了个原型的,然后在这个基础上修改下,效果还算不错,凑合用下,验证码要做到难以 ...
- ILSpy反编译工具的使用
以前一直使用reflector来查看.net类库的一些信息,不过,自2011年2月份开始,reflector就开始转向收费软件了,所以爱好免费软件的开发者们转而开发自己的反编译软件.于是ILspy就因 ...
- poj 3984 迷宫问题 bfs
学会这道水题之后我懂得了不少哈,首先水题也能学到不少知识,尤其像我这样刚入门的小菜鸟,能学到一些小技巧. 然后就是可以从别人的代码里学到不一样的思路和想法. 这题就是求最短的路径,首先想到就是用bfs ...
- android学习日记10--裁剪区域
裁剪区域 裁剪是画布的一个函数,区域可以是矩形和圆形,也可以通过设置 path 或Region来显示自定义区域,通过不同组合,Android几乎可以支持任意现状的裁剪区域.android.graphi ...
- 文件I/O之sync、fsync和fdatasync函数
传统的UNIX实现在内核中设有缓冲区高速缓存或页面高速缓存,大多数磁盘I/O都通过缓冲进行.当将数据写入文件时,内核通常先将数据复制到其中一个缓冲区中,如果 该缓冲区尚未写满,则并不将其排入输出队列, ...
- CSS字体大小设置时的参考(转)
from:http://blog.sina.com.cn/s/blog_51cd580b0100gg6y.html font-size 设置的绝对关键字: 以下几个绝对字体大小的设置是有效的.当然他们 ...
- 多边形节点编码python脚本
# -*- coding: cp936 -*-#本脚以最左边.Y值最大的点为起始点按顺时针为多边形节点编码,生成一个包含记录编码值和多边形FID字段的点要素类 #注意:#1.本脚本作为arcgis脚本 ...
- mysql的数据导入导出
1.Navicat for Mysql XML导出导入格式支持二进制数据:虽然同步数据人眼看不出区别,但是java尝试读取数据时,报datetime字段取出的值为“0000-00-00 00:00:0 ...
- 关于iOS自定义返回按钮右滑返回手势失效的解决:
在viewDidLoad方法里面添加下面这一句代码即可 self.navigationController.interactivePopGestureRecognizer.delegate=(id)s ...
- 例3-13设置ROI
写在前面,写的时候总有种给别人写的感觉,然后就写得很冗长,也没有办法很好的表达自己的想法,总觉得写得越多越好,实则不然,要最言简意赅,还能表达意思. 嗯! 只写自己不明白的地方,如果恰巧有人也看了我的 ...