谁能解释 linux 中 list_for_each_entry 和 ...entry_safe 循环的工作原理。它像是
list_for_each_entry(type *cursor, struct list_head *list, member)
list_for_each_entry_safe(type *cursor, type *next, struct list_head *list,member)
所有这些参数的作用是什么,以及它们是如何用于遍历列表的。
提前致谢
谁能解释 linux 中 list_for_each_entry 和 ...entry_safe 循环的工作原理。它像是
list_for_each_entry(type *cursor, struct list_head *list, member)
list_for_each_entry_safe(type *cursor, type *next, struct list_head *list,member)
所有这些参数的作用是什么,以及它们是如何用于遍历列表的。
提前致谢
编辑:对不起,一定很晚了,我打错了很多字。
他们很有趣!:) 不同之处在于,list_for_each_entry
如果您在迭代列表时删除某些内容并且list_for_each_entry_safe
不会(当然,以一些额外的 CPU 指令为代价),则会中断。
尽管在 list.h 中有一个巧妙的链表实现,但内核已经确定了双向链表(我假设您已经理解)。你的清单只是:
struct list_head {
struct list_head *next;
struct list_head *prev;
};
请注意,相同的结构用于列表的“头”以及每个节点。当列表为空时,头部next
和prev
成员只是指向头部自身。因此,迭代列表只是从头的成员开始并调用该节点的过程,除非它与(停止时)next
地址相同。prev
否则,将for
调用您的主体,您可以使用container_of()
宏来获取指向实际结构的指针并使用它。然后,在 的第三个字段中for
,我们只是移动到下一个next
。
编辑:哎呀,对不起,您要求对参数进行解释。好吧,如果我是你,我会直接检查它,而不是听信别人的话。对于那些,我会建议内核 API 文档本身,它至少存在于链表库中。我正在尝试获得一个补丁集,该补丁集也会将它们添加到红黑树库中,但是通过它可能是一个相当大的过程。
另请注意: http: //kernelnewbies.org/FAQ/LinkedLists
这是一个简单的例子:
struct list_head my_actual_list;
struct my_struct {
struct list_head node;
/* some other members */
};
/* in a function body somewhere... */
struct list_head *i;
list_for_each(i, &my_actual_list) {
struct my_struct *obj = list_entry(i, struct my_struct, node);
// do something with obj
}
list_entry
只是一个别名container_of
编辑#2
好的,所以在回答您在评论中的问题时,我将扩展我的答案。我实际上可以理解理解这个概念的困难,因为与 C++ STL 容器、C 数组等相比,它确实有一些奇怪的东西,但是一旦你习惯了这些习语,它就会显得很自然。还是在未来,我真的强烈建议您自己开始查看这些结构、函数和宏的定义,并尝试拼凑一个理解,然后提出问题。
因此,首先,列表中的每个节点都是一个包含 type 成员的结构,并且其自身struct list_head
的列表属于 type 。因此,在这种情况下,谁是容器,谁是被包含的对象,仅取决于它们的使用方式,但通常会以这些成员的名称来表达。迭代器的类型是。这是一个示例,我将用它们的等效代码替换正常的函数和宏调用:struct list_head
struct list_head *
struct my_container {
struct list_head list;
int some_member;
/* etc. */
};
struct my_obj {
struct list_head node;
int some_member;
/* etc. */
};
void func() {
struct my_container container;
struct my_obj obj1, obj2;
struct list_head *i;
/* INIT_LIST_HEAD(&container.list); */
container.list.next = &container.list;
container.list.prev = &container.list;
/* list_add_tail(&obj1.node); */
container.list.prev = &obj1.node;
obj1.node.next = &container.list;
obj1.node.prev = &container.list;
container.list.next = &obj1.node;
/* list_add_tail(&obj2.node); */
container.list.prev = &obj2.node;
obj2.node.next = &container.list;
obj2.node.prev = &obj1.node;
obj1.node.next = &obj2.node;
/* list_for_each(i, &container.list) { */
for (i = container.list.next; i != &container.list; i = i->next) {
struct my_obj *obj = list_entry(i, struct my_obj, node);
/* do stuff */
}
}