3-07 Linux内核链表深度分析

本文详细介绍了Linux内核中的链表数据结构,包括其基本概念、常用操作函数及使用方法,并通过具体实例展示了如何在实际项目中应用内核链表。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(本节笔记的实验代码,在这里

1.普通链表与Linux内核链表的对比

  链表是一种常用的数据结构,它通过指针将一系列数据节点连接成一条数据链。相对于数组,链表具有更好的动态性,建立链表时无需预先知道数据总量,可以随机分配空间,可以高效地在链表中的任意位置实时插入或删除数据。链表的开销主要是访问的顺序性和组织链的空间损失。
  链表分为单向节点、双向链表、循环链表和双向循环链表,Linux内核链表属于双向循环链表。
  内核链表的指针是指向下一节点的指针域,并不是指向下一节点的数据域,需要访问数据时,再通过函数访问数据域,以实现建立不同数据格式都能统一操作的链表。


2.内核链表的使用
  2.1创建链表
  2.1.1函数名:
      INIT_LIST_HEAD
  2.1.2函数原型:
      static inline void INIT_LIST_HEAD(struct list_head *list);
  2.1.3参数说明:
      *list:struct list_head结构的指针,也就是被初始化的链表头。
  2.2在链表头插入节点
  2.2.1函数名:
      list_add
  2.2.2函数原型:
  2.2.3参数说明:


  2.3在链表尾插入节点
  2.3.1函数名:
      list_add_tail
  2.3.2函数原型:
      static inline void list_add_tail(struct list_head *new,struct list_head *head);
  2.3.3参数说明:
      *new:需要插入的节点的指针域地址。
      *head:被插入的链表头地址。
  2.4删除节点
  2.4.1函数名:
      list_del
  2.4.2函数原型:
      static inline void list_del(struct list_head *entry);
  2.4.3参数说明:
      *entry:要删除的节点的指针域的指针。
  2.5取出节点
  2.5.1函数名:
      list_entry
  2.5.2函数原型:
      list_entry(ptr, type, member)
  2.5.3参数说明:
      ptr:指向节点指针域的指针。
      type:节点内容的类型。
      member:节点指针域的成员名。
  2.6遍历链表
  2.6.1函数名:
      list_for_each
  2.6.2函数原型:
      list_for_each(pos,head)
    //{
    //   for(pos = (head)->next; pos != (head); pos = pos->next)
    //   tmp = list_entry(pos,struct score, list)
    //}
    //返回的tmp是指向struct score结构的指针。
  2.6.3参数说明:
      pos:被遍历的每个节点的指针域的指针。
      head:要被遍历的链表头指针。
  学习内核函数,打开Sourceinsight参考内核代码本身!所有内核链表都保存在list.h中。
范例代码 touch mylist.c

  #include <linux/init.h>
  #include <linux/module.h>


  struct score
  {
    int num;
    int english;
    int math;
    struct list_head list;
  };


  struct list_head scorce_head;
  struct score stu1, stu2, stu3;
  struct list_head *pos;
  struct score *tmp;


  static int mylist_init()
  {
    INIT_LIST_HEAD(&score_head);            //初始化链表头
    
    stu1.num = 1;
    stu1.english = 90;
    stu1.math = 98;
    list_ade_tail(&(stu1.list), &scoure_head);    //在链表尾插入节点


    stu2.num = 2;
    stu2.english = 92;
    stu2.math = 91;
    list_ade_tail(&(stu2.list), &scoure_head);    //在链表尾插入节点


    stu3.num = 3;
    stu3.english = 94;
    stu3.math = 95;
    list_ade_tail(&(stu3.list), &scoure_head);    //在链表尾插入节点


    list_for_each(pos, &score_head)
    {
      tmp = lista_entry(pos, struct_score, list);
      printk("NO. is %d, english is %d, math is %d\n",tmp->num, tmp->english, tmp->math);
    }


    return 0;
  }


  static void mylist_exit()
  {
    list_del(&(stu1.list));
    list_del(&(stu2.list));
  }


  
  module_init(mylist_init);
  module_exit(mylist_exit);


                                                              』
touch Makefile(注意PWD为大写)

  obj-m := mylist.o
  KDIR := /arm/linux 2.6.30.4  
  all:
       make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
  clean:
          rm -f *.o *.ko *.order *.symvers


                                                              』
3.内核链表实现分析
  3.1初始化链表头
    让它的前向指针和后向指针都指向它自己。
  3.2插入节点
    指针域的前向指针和后向指针的内容更改。
  3.3取出节点
    通过member计算出节点的内容的偏移,通过偏移值来找到节点内容的地址,从而取出节点的内容。
4.移植内核链表
  直接复制内核源码中关于内核链表的代码到程序当中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值