内核驱动开发第四天linux内核链表
来源:互联网 发布:金博医疗器械软件 编辑:程序博客网 时间:2024/05/16 09:08
基本概念
1.链表是一种常用的数据结构,它通过指针
将一系列数据节点连接成一条数据链。
相
对于数组,链表具有更好的动态性,建立
链表时无需预先知道数据总量,可以随机
分配空间,可以高效地在链表中的任意位
置实时插入或删除数据。
2.链表的开销主要
是访问的顺序性和组织链的空间损失
通常链表数据结构至少包含两个域:
数据
域和指针域,数据域用于存储数据,指针
域用于建立与下一个节点的联系。
按照指
针域的组织以及各个节点之间的联系形
式,链表又可以分为单链表、双链表、循
环链表等多种类型。
在Linux内核中使用了大量的链表结
构来组织数据。这些链表大多采用
了[include/linux/list.h]中实现的一
套精彩的链表数据结构。
实现:
1.
链表数据结构的定义:
struct list_head
{
struct list_head *next, *prev;
};
list_head结构包含两个指向list_head结构指针
prev和next,
由此可见,内核的链表具备双链表功
能,实际上,通常它都组织成双向循环链表。
2.
链表操作
内核中提供的链表操作主要有:
1.初始化链表头
INIT_LIST_HEAD(list_head *head)
2.插入节点
list_add(struct list_head *new, struct list_head *head)
list_add_tail(struct list_head *new, struct list_head *head)
3.删除节点
list_del(struct list_head *entry)
4.提取数据结构
list_entry(ptr, type, member)
已知数据结构中的节点指针ptr,找出数据结
构,
例:
list_entry(aup, struct autofs, list)
5.遍历
list_for_each(struc list_head *pos, struc list_head *head)
例:
struct list_head *entry;
struct list_head cs46xx_devs; //链表头
list_for_each(entry, &cs46xx_devs)
{
card = list_entry(entry, struct cs_card, list);
if (card->dev_midi == minor)
break;
}
还有
list_for_each_entry
反向遍历
list_for_each_entry_reverse()
遍历的同时删除
list_for_each_entry_safe()
6.释放
不能使用list_for_each()和list_del()来释放链表
使用for循环和list_del ,然后使用kfree使用kmalloc分配的内存
7.移动和合并链表
把节点从一个链表移动到另一个链表
list_move()
list_move_tail()
查空
list_empty()
将两个链表合并起来
list_splice()
将两个链表合并并且重新初始化原来的链表
list_splice_init()
内核数据类型
链表,队列kfifo,映射,二叉树(红黑树)摘自linux内核设计与实现第三版
数据结构以及选择
如果对数据集合的主要操作是遍历数据,就使用链表。事实上没有数据结构可以提供比线性算法复杂度更好的算法遍历元素,所以你应该用最简单的数据结构完成简单工作。另外,当性能并非首要考虑因素时,或者当你需要存储先对较少的数据时,或者当你需要和内核中其他使用链表的代码交互时,请优先选择链表
如果你的代码符合生产者/消费者模式,则使用队列,特别是如果你想要一个定长缓冲。队列会使得添加和删除工作变得简单有效。同时队列也提供了先入先出(FIFO)语义,而这也正是生产者/消费者用例的普遍需求。另一方面,如果你需要存储一个大小不明的数据集合,那么链表可能更合适,因为你可以添加任何数量的数据项
如果你需要映射一个UID到一个对象,就使用映射。映射结构使得映射工作简单有效,而且映射可以帮你维护和分配UID。LINUX的映射接口是针对UID到指针的映射,它并不适合其他场景。但是如果你在处理发给用户空间的描述符,就考虑一下映射吧。
如果你需要存储大量数据,并且检索迅速,那么红黑树最好。红黑树可确保搜索时间复杂度是对数关系,同时也能保证按序遍历时间复杂度是线性关系。虽然他比任何数据结构复杂一些,但其对内存开销情况并不是太糟。但是如果你没有执行太多次时间紧迫的查找操作,则红黑树可能不是最好的选择,这种情况最好使用链表。
1.链表是一种常用的数据结构,它通过指针
将一系列数据节点连接成一条数据链。
相
对于数组,链表具有更好的动态性,建立
链表时无需预先知道数据总量,可以随机
分配空间,可以高效地在链表中的任意位
置实时插入或删除数据。
2.链表的开销主要
是访问的顺序性和组织链的空间损失
通常链表数据结构至少包含两个域:
数据
域和指针域,数据域用于存储数据,指针
域用于建立与下一个节点的联系。
按照指
针域的组织以及各个节点之间的联系形
式,链表又可以分为单链表、双链表、循
环链表等多种类型。
在Linux内核中使用了大量的链表结
构来组织数据。这些链表大多采用
了[include/linux/list.h]中实现的一
套精彩的链表数据结构。
实现:
1.
链表数据结构的定义:
struct list_head
{
struct list_head *next, *prev;
};
list_head结构包含两个指向list_head结构指针
prev和next,
由此可见,内核的链表具备双链表功
能,实际上,通常它都组织成双向循环链表。
2.
链表操作
内核中提供的链表操作主要有:
1.初始化链表头
INIT_LIST_HEAD(list_head *head)
2.插入节点
list_add(struct list_head *new, struct list_head *head)
list_add_tail(struct list_head *new, struct list_head *head)
3.删除节点
list_del(struct list_head *entry)
4.提取数据结构
list_entry(ptr, type, member)
已知数据结构中的节点指针ptr,找出数据结
构,
例:
list_entry(aup, struct autofs, list)
5.遍历
list_for_each(struc list_head *pos, struc list_head *head)
例:
struct list_head *entry;
struct list_head cs46xx_devs; //链表头
list_for_each(entry, &cs46xx_devs)
{
card = list_entry(entry, struct cs_card, list);
if (card->dev_midi == minor)
break;
}
还有
list_for_each_entry
反向遍历
list_for_each_entry_reverse()
遍历的同时删除
list_for_each_entry_safe()
6.释放
不能使用list_for_each()和list_del()来释放链表
使用for循环和list_del ,然后使用kfree使用kmalloc分配的内存
7.移动和合并链表
把节点从一个链表移动到另一个链表
list_move()
list_move_tail()
查空
list_empty()
将两个链表合并起来
list_splice()
将两个链表合并并且重新初始化原来的链表
list_splice_init()
内核数据类型
链表,队列kfifo,映射,二叉树(红黑树)摘自linux内核设计与实现第三版
数据结构以及选择
如果对数据集合的主要操作是遍历数据,就使用链表。事实上没有数据结构可以提供比线性算法复杂度更好的算法遍历元素,所以你应该用最简单的数据结构完成简单工作。另外,当性能并非首要考虑因素时,或者当你需要存储先对较少的数据时,或者当你需要和内核中其他使用链表的代码交互时,请优先选择链表
如果你的代码符合生产者/消费者模式,则使用队列,特别是如果你想要一个定长缓冲。队列会使得添加和删除工作变得简单有效。同时队列也提供了先入先出(FIFO)语义,而这也正是生产者/消费者用例的普遍需求。另一方面,如果你需要存储一个大小不明的数据集合,那么链表可能更合适,因为你可以添加任何数量的数据项
如果你需要映射一个UID到一个对象,就使用映射。映射结构使得映射工作简单有效,而且映射可以帮你维护和分配UID。LINUX的映射接口是针对UID到指针的映射,它并不适合其他场景。但是如果你在处理发给用户空间的描述符,就考虑一下映射吧。
如果你需要存储大量数据,并且检索迅速,那么红黑树最好。红黑树可确保搜索时间复杂度是对数关系,同时也能保证按序遍历时间复杂度是线性关系。虽然他比任何数据结构复杂一些,但其对内存开销情况并不是太糟。但是如果你没有执行太多次时间紧迫的查找操作,则红黑树可能不是最好的选择,这种情况最好使用链表。
0 0
- 内核驱动开发第四天linux内核链表
- linux驱动开发--内核链表
- linux驱动开发--内核链表
- linux 内核驱动开发
- linux驱动学习--第六天:第四章 Linux 内核模块 之 Linux 内核模块编译
- linux驱动开发-内核符号表
- 嵌入式学习-驱动开发前奏-lesson3-linux内核链表
- linux 内核驱动开发入门
- Linux 内核/驱动开发总结
- linux驱动开发--内核定时器
- Linux内核驱动开发注意事项
- Linux设备驱动&&内核开发
- Linux 内核开发 - 内核链表
- Linux内核驱动学习(六)----内核链表
- Linux内核驱动学习(六)----内核链表
- 《Linux4.0设备驱动开发详解》笔记--第四章:Linux内核模块
- linux内核第四记
- linux驱动学习--第五天:第四章 Linux 内核模块 之 Linux 内核模块简介
- Spring4 学习笔记(3)-Spring 基于 XML 的方式配置 Bean
- CalendarView组件
- HDU ACM 4535 吉哥系列故事——礼尚往来
- UIView截取图片UIimage
- POJ1321 棋盘问题 DFS
- 内核驱动开发第四天linux内核链表
- uva 719 Glass Beads (后缀自动机)
- hdu3829 二分图的最大独立集
- JAVA练习【1148】相加和最大值
- 什么是DI?
- fdsafdsafds
- iOS自带的二维码扫描功能
- MikuMikuDance V7.39 汉化版
- 字符驱动程序 (国嵌笔记)