struct student { char *name; int age; }用链表来存储多个学生,则可以在结构体加上struct student *next 指向下一个学生
struct student { char *name; int age; struct student *next; }然后可以通过链表头遍历每个学生, 这种是最常见的链表结构: 数据域,指针域
struct list_head {struct list_head *next, *prev;}; struct student { char *name; int age; struct list_head list; } struct list_head *head = &list;这样可以通过双向循环链表list, 利用container_of(head, struct student, a.list) 返回struct student a 的指针,从而访问a的数据, 如果list是链接起来的,那就可以遍历访问每个学生了
struct list_head {struct list_head *next, *prev;};// 初始化链表宏, 指向自己,则链表为空
#define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name) #define INIT_LIST_HEAD(ptr) do { \(ptr)->next = (ptr); (ptr)->prev = (ptr); \} while (0) // 运行时初始化列表初始化一个student_list 链表
LIST_HEAD(student_list)// 判断链表是否为空
static inline int list_empty(const struct list_head *head){return head->next == head;}list 循环链表插入
static inline void list_add(struct list_head *new, struct list_head *head); // 在 -> __list_add(new, head, head->next); static inline void list_add_tail(struct list_head *new, struct list_head *head); -> __list_add(new, head->prev, head); list_add(&a.list, &student_list) list_add_tail(&b.list, &student_list) static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; }循环链表删除
static inline void list_del(struct list_head *entry); list_del(&b.list); // 删除student_list b 中的链表节点链表节点移动
static inline void list_move(struct list_head *list, struct list_head *head); static inline void list_move_tail(struct list_head *list, struct list_head *head); list_move(&b.list, &student_list2) // 把b.list 从student_list 搬到student_list2 链表中链表合并
static inline void list_splice(struct list_head *list, struct list_head *head); // list 合并 到head, 新链表head链表头仍指向head static inline void list_splice_init(struct list_head *list, struct list_head *head); // 该函数在将list合并到head链表的基础上,调用INIT_LIST_HEAD(list)将list设置为空链 list_splice(&student_list, &student_list2) // student_list 合并到student_list2 链表头为原student_list2 中的链表头链表遍历
list_entry(&a.next, struct student, a.list); // 获得struct student a 结构体的指针 #define list_entry(ptr, type, member) container_of(ptr, type, member) #define container_of(ptr, type, member) ({\ const typeof( ((type *)0)->member ) *__mptr = (ptr);\ (type *)( (char *)__mptr - offsetof(type,member) );}) #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define list_for_each(pos, head) \for (pos = (head)->next, prefetch(pos->next); pos != (head); \ pos = pos->next, prefetch(pos->next)) // 遍历双向循环链表中的每一个节点, 结合list_entry 可以遍历struct student, 即list_entry(ptr, type, member) 中type 结构体的数据域, 例如 struct list_head *i; list_for_each(i, student_list) { student student *j = list_entry(i, struct student, list); printk("j->name = %s\n", j->name); } #define list_for_each_entry(pos, head, member) // 即合并list_for_each() 和 list_entry(), 大大 简化操作 struct student *i; list_for_each_entry(i, student_list, list) printk("i->name = %s\n", i->name); #define list_for_each_prev(pos, head) // 反向遍历列表节点 #define list_for_each_entry_reverse(pos, head, member) // 反向遍历列表,并且得到每个包含list的结构体指针 #define list_for_each_entry_continue(pos, head, member) // 从已知节点而不是链表头开始遍历 #define list_prepare_entry(pos, head, member) // 有时会出现如果pos有值,则从pos开始遍历,如果没有,则从链表头开始, list_prepare_entry(pos, head, member) 就是为此准备的, 可作为list_for_enach_entry_continue(pos, head, member) 中pos 的参 数
我们知道,系统中数据读取操作远多于写操作,而rwlock机制在smp环境下随着处理机增多性能会迅速下降(见参考资料4)。针对这一应用背景,IBM Linux技术中心的Paul E. McKenney提出了"读拷贝更新"的技术,并将其应用于Linux内核中。RCU技术的核心是写操作分为写-更新两步,允许读操作在任何时候无阻访问,当系统有写操作时,更新动作一直延迟到对该数据的所有读操作完成为止。Linux链表中的RCU功能只是Linux RCU的很小一部分,对于RCU的实现分析已超出了本文所及,有兴趣的读者可以自行参阅本文的参考资料;而对RCU链表的使用和基本链表的使用方法基本相同。
参考资料
http://www.ibm.com/developerworks/cn/linux/kernel/l-chain/index.html