内核驱动开发第四天linux内核链表
2015-03-10 20:39
288 查看
基本概念
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到指针的映射,它并不适合其他场景。但是如果你在处理发给用户空间的描述符,就考虑一下映射吧。
如果你需要存储大量数据,并且检索迅速,那么红黑树最好。红黑树可确保搜索时间复杂度是对数关系,同时也能保证按序遍历时间复杂度是线性关系。虽然他比任何数据结构复杂一些,但其对内存开销情况并不是太糟。但是如果你没有执行太多次时间紧迫的查找操作,则红黑树可能不是最好的选择,这种情况最好使用链表。
相关文章推荐
- Linux内核驱动学习(六)----内核链表
- linux驱动学习--第四天:第三章 linux内核以及内核编程 之 在Linux内核中新增程序的方法
- Linux内核与驱动开发学习总结:内核访问外设IO.map_desc和ioremap(七)
- Linux驱动开发环境配置(内核源码树构造)
- 浅谈 Linux 内核开发之网络设备驱动
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】全面解析Linux内核的同步与互斥机制--同步篇
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】全面解析Linux内核的同步与互斥机制--互斥篇
- linux内核驱动开发笔试题
- Linux内核N日游之内核链表
- Linux设备驱动开发详解--笔记3--Linux内核及内核编程
- Linux内核的创始人Linus Torvalds 说明了内核开发需要使用C语言而非C++的理由
- Linux内核开发之简单字符设备驱动(下)
- ubuntu下2.6.21内核的驱动开发实例
- 浅谈 Linux 内核开发之网络设备驱动[转]
- linux2.6内核驱动开发学习(1)
- 浅谈 Linux 内核开发之网络设备驱动
- ×××公司linux内核驱动开发招聘笔试题
- ×××公司linux内核驱动开发招聘笔试题
- 对贝尔阿尔卡特实施5天的Linux内核和驱动高级开发技术培训
- Linux内核开发之简单字符设备驱动(上)