Linux内核数据结构hlist_head

摘要:
structhlist_head{structhlist_node*first;};structhlist_node{structhlist_node*next,**pprev;};其内存结构如下:hlist_head结构体仅仅有一个first指针.hlist_node结构体有两个指针,next和ppre。这样的设计显然会造成链表中节点数据结构不一致,如果hlist_node采用的next和pre指针,那么对于第一个节点和其他节点操作必然会使不一致。hlist_node巧妙地将pprev指向上一个节点的next指针的地址,由于hlist_head和hlist_node指向的下一个节点的指针类型相同,这样就解决了通用性。

参考自:https://blog.csdn.net/zhanglei4214/article/details/6767288

一、hlist结构简介

hlist_head 和 hlist_node 是位于linux内核中的数据结构,其设计初衷主要是为了减少Hash表的内存消耗。

structhlist_head {
  struct hlist_node *first;
};

structhlist_node {
  struct hlist_node *next, **pprev;
};

其内存结构如下:

Linux内核数据结构hlist_head第1张

hlist_head 结构体仅仅有一个first指针.

hlist_node 结构体有两个指针,next 和 ppre。其中next指针指向下一个hlist_node,如果该节点为最后一个一个节点,那么next指向NULL。

这样设计的原因在于:通常我们在使用Hash表是为实现快速查找,那么Hash表通常会维护一张相对较大的数组,否则的会带来较大的冲突,而一张较大的数组必然会带来较大的内存消耗。我们知道通常一个Hash表中每一个dentry(每一个具体数元素)会使用两个指针,有其中一个指向尾节点,而我们知道在Hash表中的list通常是非常短(如果过长,说明冲突过多),那么显然这个指向尾节点的指向我们就不那么的必要,Hash表中的每一个denry只用保存一个指针。这样的设计显然会造成链表中节点数据结构不一致,如果hlist_node采用的next和pre指针,那么对于第一个节点和其他节点操作必然会使不一致。hlist_node巧妙地将pprev指向上一个节点的next指针的地址,由于hlist_head和hlist_node指向的下一个节点的指针类型相同,这样就解决了通用性。

二、常用接口

(1)hlist_head 和 hlist_node初始化

#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
static inline void INIT_HLIST_NODE(struct hlist_node *h) 
{
  h->next =NULL;
  h->pprev =NULL;
}

(2)添加节点

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;
}

(3)删除节点

static inline void __hlist_del(struct hlist_node *n)
{
  struct hlist_node *next = n->next;
  struct hlist_node **pprev = n->pprev;
  *pprev =next;
  if(next)
    next->pprev =pprev;
}

static inline void hlist_del(struct hlist_node *n)
{
  __hlist_del(n);
  n->next =LIST_POISON1;
  n->pprev =LIST_POISON2;
}

(4)遍历节点

#define hlist_for_each_entry(pos, head, member)       
  for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);
       pos;             
       pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))

免责声明:文章转载自《Linux内核数据结构hlist_head》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇使用element-ui二次封装一个可复用编辑表单组件转: python requests的安装与简单运用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Fuseki在linux下的部署及运行方法

在linux环境下部署并启动fuseki服务器的方法: 1.从官网上下载https://repository.apache.org/content/repositories/releases/org/apache/jena/jena-fuseki/ fuseki的工具包(名字中含有.tar的包); 2.解压缩这个包,并将其放在linux系统下,例如路径设为...

操作笔记:linux下安装mysql

1,检查linux下是否安装了mysql shell指令如下: [root@iZ945sgm0ugZ ~]# rpm -qa|grep -i mysql 如果有的话:做出挨个删除(eg:rpm -ev mysql-connector-odbc-5.2.5-6.el7.x86_64) [root@iZ945sgm0ugZ ~]# rpm -qa|grep -...

Linux最大打开文件描述符数

1.    系统最大打开文件描述符数:/proc/sys/fs/file-max a.    查看 $ cat /proc/sys/fs/file-max 186405 2. 设置 a.    临时性 # echo 1000000 > /proc/sys/fs/file-max 2.    永久性:在/etc/sysctl.conf中设置 fs.fi...

Linux环境下Gitblit服务搭建及秘钥配置

一、安装gitblit服务 1、下载地址https://pan.baidu.com/s/1wQ3TEE_gw5xZvyFPZB9xFg 2、上传至linux服务器并解压缩 tar xvf gitblit-1.8.0.tar.gz 3、修改defaults.properties文件 vim /usr/local/gitblit-1.8.0/data/defa...

Linux_配置本地YUM源(RHEL8)

【RHEL8】 Linux—RHEL8配置本地YUM 源,按照之前传统的配置本地YUM的方法肯定不行,在RHEL8版本的软件源发生了变化,在RHEL8版本的软件仓库分成了两部分:【AppStream】和【BaseOS】,所以我们在配置YUM 源的适合需要配置连个部分;具体来看操作吧! 一、配置RHEL8本地源 1、开启RHEL8的虚拟机 [root@loc...

转:Linux 编译安装 Mysql5.7

http://broqiang.com/2017/04/18/Mysql-Install-5.7.18-Linux-Compile/ 原文 Linux 编译安装 Mysql5.7 Ubuntu 下快速安装直接 apt 方式即可, 一般的开发环境也足够了 个人比较喜欢新版本,一般有新版本就会尝试一下 此文档适用于 Ubuntu 16.10 和 CentOS...