前阵子在弄缓存的时候,我们需要将qemu对于磁盘镜像文件写请求串成一个链表,最终将这个链表里面的写请求全部刷回到镜像文件里面,那么我们便需要一个强健,可靠的链表的接口,于是我们仿照Linux 2.4.0的内核,来造了这么一个链表的轮子。今天抽抽空来记录一下。

  链表,估计学过数据结构这门课程的人都对其印象深刻,因为老师们都喜欢将它放在比较靠前的地方讲,很多人都认为链表是一种非常easy的数据结构。因为链表的逻辑非常地简单,每个节点就是分成指针和数据,一头一尾地通过指针将每个节点串起来,没有树形(二叉树,B-树,红黑树,基树等)的数据结构那样复杂的前驱和后继的结构,以及复杂的结构伸展变化的操作。并且链表的各种操作的复杂度也都非常容易估算出来。

  可是,要实现一个非常可靠,通用,强健的链表数据结构却是很有难度的。

  一般地,我们都会对一个循环链表的节点做出如下的定义:

 struct node {
int val;
struct node *prev;
struct node *next;
};

  代码很简单,构造完一个链表之后会有如下的效果:

  这只是普通链表的实现,当我们需要创建另一种数据结构组成的链表的时候,如果还是按照上述的方法来创建一个链表,那么我们就不得不重新定义一个链表的节点

来存储这种数据结构,如果某个应用里面有一万种数据结构,那我们岂不要定义一万种链表的数据结构,及其查询,删除,修改的应用接口?

  我们可以尝试着将链表单独地抽离出来,对其进行解耦,这样我们便可以将他当作一套通用的应用接口来使用了。

  先来定义一下链表节点的访问入口:

typedef struct cir_list_head {
struct cir_list_head *prev, *next;
}gc_list;

  现在我们为特定的存储数据来定义一个链表的节点:

typedef struct test_list{
gc_list list;
int val;
} test_list;

注意,我们在这里就将链表节点的访问接口打包插入到了链表节点里面,仔细体会,我们最终所构建的效果如下:

接下来我们来看看如何通过gc_list * 指针来访问这些节点里面的数据:

我们希望能够通过结构体test_list里面的list(gc_list)来获取数据val,也就是说在同一个结构体下,通过其中一个结构体成员来获取另一个结构体成员的信息,

这个时候,我们就需要用到一些奇技淫巧:

#define OFFSETOF(type, member)        (size_t)&(((type *)0)->member)

#define container_of(ptr, type, member) ({                      \
const typeof( ((type *))->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - OFFSETOF(type,member) );})

盗用一幅图描述上面的这几行代码的意思,不用太多的文字的解释~~,通过上面的这个接口我们便可以随意地操控循环链表里面的各种数据啦~,这种封装方法

比较好的地方便是你再也不用为每一种链表里面的数据特意去重写一套API,注意这段代码和编译器平台相关(主要都在GCC平台下),并不具备100%的可移植性。

相关链接:

  造的一个循环链表的轮子:https://github.com/jusonalien/VM-DB/blob/master/list.h

  测试使用代码:https://github.com/jusonalien/VM-DB/blob/master/TestList.c

  关于container_of宏的详尽的解释: http://radek.io/2012/11/10/magical-container_of-macro/

浅谈Linux Kernel 中循环链表的实现的更多相关文章

  1. (转)浅谈 Linux 系统中的 SNMP Trap

    原文:https://www.ibm.com/developerworks/cn/linux/l-cn-snmp/index.html 简介 本文讲解 SNMP Trap,在介绍 Trap 概念之前, ...

  2. 浅谈Linux系统中如何查看进程

    进程是一个其中运行着一个或多个线程的地址空间和这些线程所需要的系统资源.一般来说,Linux系统会在进程之间共享程序代码和系统函数库,所以在任何时刻内存中都只有代码的一份拷贝. 1,ps命令 作用:p ...

  3. 浅谈Linux系统中如何查看进程 ——ps,pstree,top,w,全解

    进程是一个其中运行着一个或多个线程的地址空间和这些线程所需要的系统资源.一般来说,Linux系统会在进程之间共享程序代码和系统函数库,所以在任何时刻内存中都只有代码的一份拷贝. 1,ps命令 作用:p ...

  4. 浅谈linux系统中pdf文件的默认打开方式

    atril.gimp和evince,三者均可以打开application/pdf格式文件.gimp为一款图像处理软件:atril为mate环境下常用的文档查看器:evince为gnome环境下常用的文 ...

  5. 浅谈Linux中的信号处理机制(二)

    首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...

  6. Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理

    Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理 转自:https://www.jianshu.com/p/2b71ea919d49 本系列文章首发于我的个人博 ...

  7. 浅谈linux中shell变量$#,$@,$0,$1,$2,$?的含义解释

    浅谈linux中shell变量$#,$@,$0,$1,$2,$?的含义解释 下面小编就为大家带来一篇浅谈linux中shell变量$#,$@,$0,$1,$2的含义解释.小编觉得挺不错的,现在就分享给 ...

  8. 浅谈 Linux 内核无线子系统

    浅谈 Linux 内核无线子系统 本文目录 1. 全局概览 2. 模块间接口 3. 数据路径与管理路径 4. 数据包是如何被发送? 5. 谈谈管理路径 6. 数据包又是如何被接收? 7. 总结一下 L ...

  9. (转)浅谈 Linux 内核无线子系统

    前言 Linux 内核是如何实现无线网络接口呢?数据包是通过怎样的方式被发送和接收呢? 刚开始工作接触 Linux 无线网络时,我曾迷失在浩瀚的基础代码中,寻找具有介绍性的材料来回答如上面提到的那些高 ...

随机推荐

  1. unittest多线程生成报告(BeautifulReport)

    前言 selenium多线程跑用例,这个前面一篇已经解决了,如何生成一个测试报告这个是难点,刚好在github上有个大神分享了BeautifulReport,完美的结合起来,就能生成报告了. 环境必备 ...

  2. 动手实操(一):如何用七牛云 API 实现相片地图?

    实操玩家: 在苹果手机上,我们只要打开定位服务,拍照后便能在相簿中找到地图,地图上显示着在各地拍摄的相片.网站上这种显示方式也并不少见,例如 Flickr.即将关闭的 Panoramio 等. 作为地 ...

  3. IntelliJ IDEA平台下JNI编程—HelloWorld篇

    转载请注明出处:[huachao1001的专栏:http://blog.csdn.net/huachao1001/article/details/53906237] JNI(Java Native I ...

  4. 希尔排序(shell)

    希尔排序: 思路: 希尔排序是插入排序的一种改进的版本. 先将整个待排序记录序列分割成若干个子序列,在在序列内分别进行直接插入排序,待整个序列基本有序时,再对全体记录进行一次直接插入排序. 这里增量序 ...

  5. Git学习之常见错误 git push 失败

    Git学习之常见错误 git push 失败 问题描述: git push Counting objects: , done. Delta compression using up to thread ...

  6. HDU 1074 Doing Homework【状态压缩DP】

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1074 题意: 给定作业截止时间和完成作业所需时间,比截止时间晚一天扣一分,问如何安排作业的顺序使得最 ...

  7. 洛谷——P3225 [HNOI2012]矿场搭建

    P3225 [HNOI2012]矿场搭建 题目描述 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤 ...

  8. 前端开发数据mock神器 -- xl_mock

    1.为什么要实现数据 mock 要理解为什么要实现数据 mock,我们可以提供几个场景来解释, 1.现在的开发很多都是前后端分离的模式,前后端的工作是不同的,当我们前端界面已经完成,但是后端的接口迟迟 ...

  9. js的基础(平民理解的执行上下文/调用堆栈/内存栈/值类型/引用类型)

    与以前的切图比较,现在的前端开发对js的要求似乎越来越高,在开发中,我们不仅仅是要知道如何运用现有的框架(react/vue/ng), 而且我们对一些基础的知识的依赖越来越大. 现在我们就用平民的方法 ...

  10. 元数据的概念以及相关的操作os模块、shutil模块

    查看文件的元数据 stat [OPTION]… FILE… OPTION: -f 输出文件系统的状态,而非文件的状态 -t 显示简要格式的文件元数据信息 FILE:可同时查看多个文件的元数据信息,多个 ...