文章目录
- 一、Hash表简介
- 二、相关结构
- 三、相关函数
- 3.1 定义Hash表
- 3.2 Hash表初始化
- 3.3 Hash表添加元素
- 3.4 Hash表遍历
- 3.6 Hash表元素删除
一、Hash表简介
- 哈希表(Hash table)又叫散列表,是根据(Key, Value) 键值对进行访问的数据结构。主要目的是提高查询效率,比如Hash表的order为5,也就是同时使用
2^5
个链表,理论上查询速度可以比链表快2^ 5
倍,典型的以空间换时间。 - 主要实现在 include/linux/hashtable.h 中,基于hlist。
- 在 Linux 内核中,Hash Table 和 RCU 是经常一起使用的。Hash Table 主要用于快速查找元素,而 RCU 用于读操作的并发保护,以便多个线程能够同时访问 Hash Table。
- 使用 Hash Table 时,需要特别注意并发读写的正确性,以避免数据不一致等问题。使用 RCU 可以有效地提高 Hash Table 的并发读取性能,并减少锁竞争。
二、相关结构
/* include/linux/types.h *//*哈希表表头结构*/
struct hlist_head {struct hlist_node *first; //指向头结点的指针
};/*结点结构*/
struct hlist_node {struct hlist_node *next, **pprev; // next指向下一结点的指针,pprev指向上一结点next指针的指针
};
使用二级指针 **pprev 可以使在删除节点上的处理变的简单,无需关心是否是head节点。而单链表或双向链表使用 *prev 成员需要单独判断是否是head节点。
三、相关函数
3.1 定义Hash表
/* Hash表的表头就是一个数组,数组中每一个原生都是一个链表 */
#define DECLARE_HASHTABLE(name, bits) \struct hlist_head name[1 << (bits)]/* 定义并初始化 */
#define DEFINE_HASHTABLE(name, bits) \struct hlist_head name[1 << (bits)] = \{ [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT }
3.2 Hash表初始化
/* 初始化Hash表 */
#define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable))static inline void __hash_init(struct hlist_head *ht, unsigned int sz)
{unsigned int i;for (i = 0; i < sz; i++)INIT_HLIST_HEAD(&ht[i]);
}
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
3.3 Hash表添加元素
/*** hash_add - add an object to a hashtable* @hashtable: hashtable to add to* @node: the &struct hlist_node of the object to be added* @key: the key of the object to be added*/
#define hash_add(hashtable, node, key) \hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])/*** hash_add_rcu - add an object to a rcu enabled hashtable* @hashtable: hashtable to add to* @node: the &struct hlist_node of the object to be added* @key: the key of the object to be added*/
#define hash_add_rcu(hashtable, node, key) \hlist_add_head_rcu(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
3.4 Hash表遍历
/*** hash_for_each - iterate over a hashtable* @name: hashtable to iterate* @bkt: integer to use as bucket loop cursor* @obj: the type * to use as a loop cursor for each entry* @member: the name of the hlist_node within the struct*/
#define hash_for_each(name, bkt, obj, member) \for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\(bkt)++)\hlist_for_each_entry(obj, &name[bkt], member)/*** hash_for_each_rcu - iterate over a rcu enabled hashtable* @name: hashtable to iterate* @bkt: integer to use as bucket loop cursor* @obj: the type * to use as a loop cursor for each entry* @member: the name of the hlist_node within the struct*/
#define hash_for_each_rcu(name, bkt, obj, member) \for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\(bkt)++)\hlist_for_each_entry_rcu(obj, &name[bkt], member)/*** hash_for_each_safe - iterate over a hashtable safe against removal of* hash entry* @name: hashtable to iterate* @bkt: integer to use as bucket loop cursor* @tmp: a &struct hlist_node used for temporary storage* @obj: the type * to use as a loop cursor for each entry* @member: the name of the hlist_node within the struct*/
#define hash_for_each_safe(name, bkt, tmp, obj, member) \for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\(bkt)++)\hlist_for_each_entry_safe(obj, tmp, &name[bkt], member)/*** hash_for_each_possible - iterate over all possible objects hashing to the* same bucket* @name: hashtable to iterate* @obj: the type * to use as a loop cursor for each entry* @member: the name of the hlist_node within the struct* @key: the key of the objects to iterate over*/
#define hash_for_each_possible(name, obj, member, key) \hlist_for_each_entry(obj, &name[hash_min(key, HASH_BITS(name))], member)/*** hash_for_each_possible_rcu - iterate over all possible objects hashing to the* same bucket in an rcu enabled hashtable* @name: hashtable to iterate* @obj: the type * to use as a loop cursor for each entry* @member: the name of the hlist_node within the struct* @key: the key of the objects to iterate over*/
#define hash_for_each_possible_rcu(name, obj, member, key, cond...) \hlist_for_each_entry_rcu(obj, &name[hash_min(key, HASH_BITS(name))],\member, ## cond)/*** hash_for_each_possible_rcu_notrace - iterate over all possible objects hashing* to the same bucket in an rcu enabled hashtable in a rcu enabled hashtable* @name: hashtable to iterate* @obj: the type * to use as a loop cursor for each entry* @member: the name of the hlist_node within the struct* @key: the key of the objects to iterate over** This is the same as hash_for_each_possible_rcu() except that it does* not do any RCU debugging or tracing.*/
#define hash_for_each_possible_rcu_notrace(name, obj, member, key) \hlist_for_each_entry_rcu_notrace(obj, \&name[hash_min(key, HASH_BITS(name))], member)/*** hash_for_each_possible_safe - iterate over all possible objects hashing to the* same bucket safe against removals* @name: hashtable to iterate* @obj: the type * to use as a loop cursor for each entry* @tmp: a &struct hlist_node used for temporary storage* @member: the name of the hlist_node within the struct* @key: the key of the objects to iterate over*/
#define hash_for_each_possible_safe(name, obj, tmp, member, key) \hlist_for_each_entry_safe(obj, tmp,\&name[hash_min(key, HASH_BITS(name))], member)
3.6 Hash表元素删除
/*** hash_del - remove an object from a hashtable* @node: &struct hlist_node of the object to remove*/
static inline void hash_del(struct hlist_node *node)
{hlist_del_init(node);
}/*** hash_del_rcu - remove an object from a rcu enabled hashtable* @node: &struct hlist_node of the object to remove*/
static inline void hash_del_rcu(struct hlist_node *node)
{hlist_del_init_rcu(node);
}
参考链接
- linux内核数据结构分析之哈希表
- 内核Hash表hlist
- Linux:内核hash表——hlist
- linux内核数据结构—hash表