四,哈希链表
谈到链表就不得不谈Linux内核中另外一个重要的结构,哈希链表。讨论这个结构前,你需要对哈希的最基本的概念要清楚哦,由于我们已经讲过Linux内核中的普通链表的结构,这里我们对比他们的区别来了解哈希链表会直观一些。
Linux链表认为双指针表头双循环链表对于HASH表来说过于浪费,因而设计了一套用于HASH表的hlist的数据结构,单指针表头双循环链表。hlish表头仅有一个指向首节点的指针,而没有指向尾节点的指针,这样在海量的HASH表中存储的表头就能减少一半的空间消耗。
- 定义和初始化
我们先来看看哈希链表头的定义以及哈希链表节点的定义。
此定义在include/linux/types.h中可以看到:
struct hlist_head {
struct hlist_node *first; //指向每一个hash桶的第一个结点的指针
};
struct hlist_node {
struct hlist_node *next, **pprev; //pprev是指向上一个结点的next指针的地址
};
所以从定义上我们就可以知道哈希链表和内核普通双向链表的节点唯一的区别就在于,pprev是个两级指针,为什么是二级指针我们稍后会仔细讨论,了解哈希算法的同学就知道哈希链表并不需要双向循环的技能,它一般适用于单向散列的场景。再加上前面提到的节省存储空间的考虑,在嵌入式设备领域是非常明智的选择。
此外在include/linux/list.h中包含链表的相关初始化操作,本章节后续除非特意说明代码皆出自本文件。
#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
初始化哈希桶,INIT_HLIST_HEAD,哈希链表头节点初始化为NULL
INIT_HLIST_HEAD
初始化哈系桶中的每一个节点
static inline void INIT_HLIST_NODE(struct hlist_node *h)
{
h->next &