学习笔记《Linux内核分析与应用》1.4源码分析-内核中的哈希表

学习笔记《Linux内核分析与应用》1.4源码分析-内核中的哈希表

  • 哈希冲突链表
    • 删除链表中的节点

LINUX内核分析与应用是西安邮电大学,陈莉君教授的课程。在B站上有视频讲解,非常精彩。我是自己在学习《深入理解Linux内核》这本书的时候,同事推荐给我看的。这里也向大家推荐。
我自己的笔记主要记录自己不甚了了的内容。

哈希冲突链表

学习笔记《Linux内核分析与应用》1.4源码分析-内核中的哈希表_第1张图片

删除链表中的节点

这里特殊的是采用了一个二级指针,稍微有点绕。

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

为了方便理解我对应每一条语句分步来画出链表的情况:
学习笔记《Linux内核分析与应用》1.4源码分析-内核中的哈希表_第2张图片
x实际上应该是node n-1的next的地址。这样我们就可以直接修改其内容,达到使其指向被删除节点node n的下一个节点node n+1的目的。
学习笔记《Linux内核分析与应用》1.4源码分析-内核中的哈希表_第3张图片
下面探讨一下pprev定义为二级指针的原因。

  1. 如果去掉pprev变为单向链表,插入比较简单可以采用头部插入,查找同样是从头开始遍历。但是在删除节点时,前面节点需要遍历才能找到。效率低。
  2. 如果把pprev变为一级指针prev,这样链表变为普通的双向链表。但是因为哈希表链表有两种不同的节点:head和node
    struct hlist_head {
        struct hlist_node *first;
    };
    struct hlist_node {
        struct hlist_node *next, **pprev;
    };
    
    如果使用普通双向链表,指向头节点的prev指针要进行强制转换。这种操作是危险的,在进行KW或者Coverity扫描的时候会报错,甚至很多编译器也不允许。
    如果将头结点也定义为node,这样头节点就多了一个无用的指针类型,而且在哈希的数组中,每个元素都有一个头节点类型,相当于每个节点都增加了一个地址指针。由于内核的内存空间限制,所以这种无意义的浪费是不能容忍的。

你可能感兴趣的:(Linux内核,链表,内核,操作系统,linux)