Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 双指针在linux内核哈希表实现中的应用_C_Linux_Linux Kernel - Fatal编程技术网

C 双指针在linux内核哈希表实现中的应用

C 双指针在linux内核哈希表实现中的应用,c,linux,linux-kernel,C,Linux,Linux Kernel,我试图理解Linux内核中链表和哈希表的实现。与实现的链接是。我理解链表的实现。但我不太明白为什么在hlist(**pprev)中使用双指针。hlist的链接是。我知道hlist用于哈希表的实现,因为列表的头只需要一个指针,这样可以节省空间。为什么不能使用单指针(就像链表一样*prev)?请帮助我。原因可以在以下评论中找到: 547/* 548 * Double linked lists with a single pointer list head. 549 * Mostly usefu

我试图理解Linux内核中链表和哈希表的实现。与实现的链接是。我理解链表的实现。但我不太明白为什么在hlist(**pprev)中使用双指针。hlist的链接是。我知道hlist用于哈希表的实现,因为列表的头只需要一个指针,这样可以节省空间。为什么不能使用单指针(就像链表一样*prev)?请帮助我。

原因可以在以下评论中找到:

 547/*
 548 * Double linked lists with a single pointer list head.
 549 * Mostly useful for hash tables where the two pointer list head is
 550 * too wasteful.
 551 * You lose the ability to access the tail in O(1).
 552 */
如果您使用的是*prev而不是**pprev,并且因为我们试图节省内存,所以在头部不包含*prev,那么我们的hlist实现如下所示:

struct hlist_head {
  struct hlist_node *first = null;
};

struct hlist_node {
  struct hlist_node *next;
  struct hlist_node *prev;
};
void
hlist_add_before(struct hlist_head *head,
                 struct hlist_node *node,
                 struct hlist_next *next) {
  hlist_node *prev = next->prev;

  node->next = next;
  node->prev = prev;
  next->prev = node;

  if (prev) {
    prev->next = node;
  } else {
    head->first = node;
  }
}
请注意,
prev
指针不能指向头部或
head->first
(与
**pprev
不同)。这使hlist实现复杂化,当我们实现
hlist\u add\u before()
时,您将看到这一点:

请注意,
prev
在上面的
hlist\u add\u head()
的IME实现中没有任何指向。因此,现在当您实现
hlist\u add\u before()
时,它如下所示:

struct hlist_head {
  struct hlist_node *first = null;
};

struct hlist_node {
  struct hlist_node *next;
  struct hlist_node *prev;
};
void
hlist_add_before(struct hlist_head *head,
                 struct hlist_node *node,
                 struct hlist_next *next) {
  hlist_node *prev = next->prev;

  node->next = next;
  node->prev = prev;
  next->prev = node;

  if (prev) {
    prev->next = node;
  } else {
    head->first = node;
  }
}
请注意,现在我们需要传入
head
以及
hlist\u add\u before()
,这需要一个额外的
push
指令来推动堆栈上的
head
。此外,在实现中还有一个额外的条件检查,这进一步降低了速度


现在,尝试用
*prev
而不是
**pprev
实现其他hlist操作,您会发现您的实现将比您在linux内核中看到的慢。

有两种类型的列表:常规列表头类型和哈希列表(hlist)。“列表头”类型只有一个结构,即“结构列表头”。但是hlist有两个结构,“struct hlist_head”和“struct hlist_node”。因此,对于hlist,当试图指向上一个元素时,该元素可以是“hlist\u head”或“hlist\u node”类型。我们不能使用一个通用指针类型来指向这两种元素类型。(当然,我们可以使用void*,但它不是一种好的指针类型,在实际使用它之前需要进行类型转换),因此解决方案是让“prev”指针指向一个公共结构类型,即“struct hlist_node*”。此公共类型由hlist_head中的字段“first”和hlist_节点中的字段“next”共享。因此,“prev”指针变为“struct hlist_node**”,可以指向hlist_head.first和hlist_node.next。

谢谢您的回答。但我的疑问是为什么没有*prev和双链接列表。使用此选项可以双向遍历。可以在O(1)中添加和删除节点。两种情况下使用的内存相同。很明显,我遗漏了一些东西。您能指出我的错误吗?我无法通过使用hlist找到性能增益。你能解释一下吗?