转载时请注明出处和作者联系方式:http://blog.csdn.net/mimepp
作者联系方式:YU TAO <yut616 at sohu dot com>
list head在应用程序中的使用和注意事项
kernel中经常使用的 list head 连接件,在一般的应用程序中也有很好的应用价值,这里做个笔记。
list head 里面只有prev, next,而没有数据部分,这个是它和我们一般用法上的linked list的最大的不同,而且它也要灵活很多 。
例子代码:/usr/src/linux-headers-2.6.28-11-generic/include/linux/list.h
struct list_head { struct list_head *next, *prev; };
而且 list_entry 的做法也很特殊。
我们可以自己写个小程序验证一下 list entry 的特性。
#include <stdio.h> #include <stdlib.h> struct test_s { int a; int b; }; void main() { struct test_s hello; printf("%p, %d/n", &(((struct test_s*)0)->b), ((struct test_s*)0)->b); }
(gdb) b test.c:11 Breakpoint 1 at 0x80483d5: file test.c, line 11. (gdb) r Starting program: /work/a.out Breakpoint 1, main () at test.c:11 11 printf("%p, %d/n", &(((struct test_s*)0)->b), ((struct test_s*)0)->b); (gdb) p &(((struct test_s*)0)->b) $1 = (int *) 0x4 (gdb) p ((struct test_s*)0)->b Cannot access memory at address 0x4
这里可以看出对指针 &(((struct test_s*)0)->b) 的访问是允许的,而对其中所对应的内容进行访问是非法的。
注意事项:
1、线程安全
在实际的使用中,还要特别注意 list_for_each_safe 的使用,需要指出的是,list_for_each_safe 对多线程是不安全的,它只是在当前单一进程是safe的。
如果在多线程中使用,就需要自己加 lock 来保护对 list 的操作。
2、list 中 head 的位置
#define list_for_each(pos, head) / for (pos = (head)->next; prefetch(pos->next), pos != (head); / pos = pos->next)
从这个循环中,我们可以看到 pos 是从 head->next开始的,直到不为 head 结束,也就是说,list 里是有 head 的,这个和一般的 linked list 也有不同,一般地操作是从第一个操作到最后一个,而 list head 却不是。
这个主要是由于 head 没有对应的 entry,所以是跳过它来对其他 pos 来操作的。