Linux内核之—内核链表二

来源:互联网 发布:java编程思想是什么 编辑:程序博客网 时间:2024/05/01 11:15

 二: 内核链表的实现接口

 

      1. 链表的初始化

 

       链表的初始化并没有建立链表的头部,而是将struct list_head结构体中的两个指针指向自己。例如我们在初始化一个名为node的链表时,我们可以采用下面两种方式进行初始化:

 

        1.1、静态初始化:静态初始化就是在声明的同时初始化链表。

        初始化的方法为:   LIST_HEAD(node) ;

        在内核中LIST_HEAD()是一个宏定义,内核中的实现方式是:

        #define LIST_HEAD_INIT(name)  {&(name),&(name)}

        #define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name);

 

       1.2、 动态初始化:在初始化前,需要定义一个链表的结构体。

        初始化的方法为:  struct list_head node;

                                   INIT_LIST_HEAD(&node);

        在内核中INIT_LIST_HEAD()也是一个宏定义,内核中的实现方式为:

        #define INIT_LIST_HEAD(ptr)  do { /

                               (ptr)->next = (ptr);/

                               (ptr)->prev = (ptr);/

                              }while(0);                      

 

       2. 插入、删除、合并接口

 

      2.1、内核链表的插入可以分为插入到链表的首部和插入到链表的尾部。分别通过函数:

      static inline void list_add(struct list_head *new, struct list_head *head);
      static inline void list_add_tail(struct list_head *new, struct list_head *head);

      由于linux内核链表是一种循环链表,所以加入到链表的首部或者是链表的尾部都是一样的,两者调用的函数都是

      __list_add(),只是调用的时候的实参不一样而已。__list_add()的实现原理如下:

      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;
    };

    2.2、内核链表的删除提供了两个函数接口,分别为:

    static inline void list_del(struct list_head *entry);

    static inline void list_del_init(struct list_head *entry);

    这两个函数的目的相同,在实现方式上都是调用__list_del();不同的是,前者删除节点后,并将删除后的节点的两个指针

    赋值为LIST_POSITION1和LIST_POSITION2,后者是将节点删除后,并肩删除后的节点的指针指向删除的节点本身

    (即调用了LIST_INIT_HEAD())。

    2.3、移除:是指将节点从一个链表删除并将该节点加入到另外的一个链表中。

    移除的实现原理就是删除和添加的一个结合体,所以,在添加到另外的一个链表时,可以添加到首部也可以使尾部

    所以,他的实现函数有两个,分别是:

    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);
    2.4、合并:是将两个链表合并为一个链表。合并的实现函数为:

    static inline void list_splice(struct list_head *list, struct list_head *head);

    static inline void list_splice_init(struct list_head *list, struct list_head *head);

    它的实现原理图如下:

     链表合并list_splice(&list1,&list2)

 

 

    3、链表的遍历

     链表的遍历就是将从头开始访问链表中的每一个节点,直到起始节点为止。链表的遍历有下一个依次遍历也可以从前一个 

     依次遍历,遍历的目的是为了找出链表中每个节点中的数据域内容,所以,我们在遍历的时候需要另外一个能提取数据域的

     函数list_entry()。为了保证遍历时的安全性,我们可以在遍历中加入判断,判断当前的节点指针是不是一个空值,或者

     采用函数,list_empty( )判断是不是结束。

     遍历的函数:  list_for_each(pos, head);              //正常的遍历

                            list_for_each_prev(pos, head)    //反向遍历

       第一个参数为一个struct list_head *的指针,他的值随着遍历指向链表中的各个节点。

       第二个参数为我们初始化的一个链表头部。

       获取数据的函数: list_entry(ptr, type, member);

       第一个参数为一个struct list_head *的指针,它的位置是读取链表中哪个位置的数据。

       第二个参数是带有该链表的结构体的类型。

       第三个参数是该结构体中链表类型的变量。

       例如:我们在遍历一个初始化一个一个链表lst,并将几个struct node元素加入到链表后,开始遍历该链表。

      struct list_head  *p_list;  

      list_for_each(p_list,&lst)

      {

            struct node *cur = list_entry(p_list,struct node,list);

            if(cur == NULL)

                   break;

             printk("data = %s/n",cur->data);

     }

 

    附:链表的一个例子

 

 

原创粉丝点击