数据结构(3)内核链表
一、内核链表
内核链表是一种在操作系统内核中使用的数据结构,主要用于管理和组织内核对象。它是有头双向链表的一种实现。
内核链表的特点
-
双向链表: 内核链表的每个节点都包含指向前一个节点和后一个节点的指针,这使得在链表中进行插入和删除操作时更加高效。
-
高效性: 内核链表的操作通常在内核空间中进行,避免了用户空间和内核空间之间的上下文切换,从而提高了性能。
-
简化的接口: 内核链表通常提供了一组宏和函数来简化链表的操作,例如添加、删除和遍历节点。这些操作通常是以宏的形式实现,以减少函数调用的开销。
1. offsetof
offsetof
是一个宏,用于获取结构体中某个成员相对于结构体起始位置的字节偏移量。它的定义通常如下:
#define offsetof(type, member) ((size_t) &((type *)0)->member)
用法
-
参数:
type
: 结构体的类型。member
: 结构体中的成员名。
-
返回值: 返回指定成员相对于结构体起始位置的字节偏移量。
2. container_of
container_of
是一个宏,用于根据结构体成员的指针获取包含该成员的结构体的指针。它的定义通常如下:
#define container_of(ptr, type, member) \ ((type *)((char *)(ptr) - offsetof(type, member)))
用法
-
参数:
ptr
: 指向结构体成员的指针。type
: 结构体的类型。member
: 结构体中的成员名。
-
返回值: 返回指向包含该成员的结构体的指针。
二、内核链表的实现
KNode_t:代表链表中的一个节点。
包含两个指针:
ppre: 指向前一个节点的指针。
pnext: 指向下一个节点的指针。
typedef struct knode
{ struct knode *ppre; struct knode *pnext;
} KNode_t;
KLink_t:代表整个链表。
包含以下成员:
phead: 指向链表头节点的指针。
clen: 当前链表中的节点数量。
mutex: 用于线程安全的互斥锁,确保在多线程环境中对链表的操作是安全的。
typedef struct klink
{ KNode_t *phead; int clen; pthread_mutex_t mutex;
} KLink_t;
1. create_klink
KLink_t *create_klink()
{ KLink_t *pklink = malloc(sizeof(KLink_t)); if (NULL == pklink) { perror("fail malloc"); return NULL; } pklink->phead = NULL; pklink->clen = 0; pthread_mutex_init(&(pklink->mutex), NULL); return pklink;
}
功能: 创建一个新的链表。
步骤:
使用 malloc 分配内存。
检查内存分配是否成功。
初始化链表头指针为 NULL,节点计数为 0,并初始化互斥锁。
返回值: 返回指向新链表的指针。
2. push_klink_head
int push_klink_head(KLink_t *pklink, void *p)
{ KNode_t *pnode = (KNode_t *)p; pnode->pnext = NULL; pnode->ppre = NULL; pnode->pnext = pklink->phead; if (pklink->phead != NULL) { pklink->phead->ppre = pnode; } pklink->phead = pnode; pklink->clen++; return 0;
}
功能: 将一个节点插入到链表的头部。
步骤:
将传入的节点指针 p 转换为 KNode_t 类型。
设置新节点的前后指针。
将新节点插入到链表头部,并更新头指针。
增加链表的节点计数。
返回值: 返回 0 表示成功。
3. klink_for_each
void klink_for_each(KLink_t *pklink, void (*pfun)(void *))
{ KNode_t *pnode = pklink->phead; while (pnode != NULL) { pfun(pnode); pnode = pnode->pnext; } printf("\n");
}
功能: 遍历链表并对每个节点执行指定的函数。
参数:
pklink: 指向链表的指针。
pfun: 指向处理每个节点的函数的指针。
步骤:
从链表头开始遍历,调用传入的函数处理每个节点。
4. push_klink_tail
int push_klink_tail(KLink_t *pklink, void *q)
{ KNode_t* pnode = (KNode_t*)q; pnode->pnext = NULL; pnode->ppre = NULL; if (NULL == pklink->phead) { pklink->phead = pnode; } KNode_t* p = pklink->phead; while (p->pnext) { p = p->pnext; } p->pnext = pnode; pnode->ppre = p; return 0;
}
功能: 将一个节点插入到链表的尾部。
步骤:
将传入的节点指针 q 转换为 KNode_t 类型。
设置新节点的前后指针。
如果链表为空,将新节点设置为头节点。
否则,遍历到链表的最后一个节点,并将新节点添加到尾部。
返回值: 返回 0 表示成功。
5. pop_klink_head
int pop_klink_head(KLink_t *pklink)
{ if (NULL == pklink->phead) { return 0; } KNode_t* pnode = pklink->phead; pklink->phead = pnode->pnext; if (pklink->phead != NULL) { pklink->phead->ppre = NULL; } free(pnode); return 0;
}
功能: 从链表的头部删除一个节点。
步骤:
检查链表是否为空。
保存当前头节点,并将头指针更新为下一个节点。
如果新的头节点不为空,更新其前指针。
释放被删除节点的内存。
返回值: 返回 0 表示成功。
三、内核链表和普通双向链表的区别
1. 目的和使用场景
-
内核链表:
- 主要用于操作系统内核中,处理任务调度、资源管理、设备驱动等。
- 需要高效的插入、删除和遍历操作,以满足实时性和性能要求。
-
普通双向链表:
- 通常用于应用程序中,处理数据存储、缓存、队列等。
- 设计上更关注易用性和灵活性,而不是极端的性能优化。
2. 结构和实现
-
内核链表:
- 通常使用更简洁的结构,可能不包含数据部分,节点结构只包含指向前后节点的指针。
- 数据部分通常与链表分开,链表节点只负责链接,数据通过其他方式管理。
-
普通双向链表:
- 节点结构通常包含数据部分和指向前后节点的指针。
- 每个节点都是完整的,包含数据和指针,便于直接操作。
3. 线程安全
-
内核链表:
- 设计时通常考虑到多线程环境,可能会使用互斥锁或其他同步机制来确保线程安全。
- 需要处理并发访问,确保数据一致性。
-
普通双向链表:
- 通常不考虑线程安全,使用时需要开发者自行管理。
- 在单线程环境中使用时,简单易用,但在多线程环境中可能会出现数据竞争问题。
相关文章:
数据结构(3)内核链表
一、内核链表 内核链表是一种在操作系统内核中使用的数据结构,主要用于管理和组织内核对象。它是有头双向链表的一种实现。 内核链表的特点 双向链表: 内核链表的每个节点都包含指向前一个节点和后一个节点的指针,这使得在链表中进行插入和删除操作时更…...

Linux 硬件学习 s3c2440 arm920t蜂鸣器
1.查找手册时钟图,输入12m想要通过pll得到400m的信号 2.对比pll值,找到最近的为405,得到pll中mdiv为127,pdiv为2,sdiv为1 3.想要得到fclk400,hclk100,pclk50,对比分频比例࿰…...
提交保存,要做重复请求拦截,避免出现重复保存的问题
**问题:**前端ajax提交数据的时候,当频繁点击的时候,或者两个账号以相同数据创建的时候,会出现问题。 **处理办法:**前端拦截,防止重复提交数据,在上一次请求返回结果之后才允许提交第二次&…...
华为 HCIP-Datacom H12-821 题库 (3)
有需要题库的可以看主页置顶 1.运行 OSPF 协议的路由器在交互 DD 报文时,会使用以下哪一个参数选举主从关系? A、接口的 IP 地址 B、接口的 DR 优先级 C、Area ID D、Router ID 答案:D 解析: Router-ID 大的为主&a…...
spring-boot 事件
事件触发时机常用监听器描述ApplicationStartingEvent应用启动时LoggingApplicationListener:决定加载哪个日志系统ApplicationEnvironmentPreparedEvent创建Environment之后BootstrapApplicationListener:加载spring-cloud bootstrap配置文件࿱…...

合碳智能 × Milvus:探索化学合成新境界——逆合成路线设计
合碳智能(C12.ai)成立于2022年,致力于运用AI和具身智能技术,为药物研发实验室提供新一代智能化解决方案,推动实验室从自动化迈向智能化,突破传统实验模式与人员的依赖,解决效率和成本的瓶颈&…...

二分查找 | 二分模板 | 二分题目解析
1.二分查找 二分查找的一个前提就是要保证数组是有序的(不准确)!利用二段性! 1.朴素二分模板 朴素二分法的查找中间的值和目标值比较 while(left < right) // 注意是要: < {int mid left (right -left) / 2;…...

uni-app应用更新(Android端)
关于app更新,uni-app官方推荐的是 uni-upgrade-center,看了下比较繁琐,因此这里自己实现检查更新并下载安装的逻辑。 1.界面效果 界面中的弹框和 进度条采用了uView 提供的组件 2.检查更新并下载安装 一、版本信息配置在服务端,…...

JavaEE(2):前后端项目之间的交互
现在,在网页中通过超链接,表单就可以向后端发送请求,后端也可以正常响应内容。 以前通过表单访问后端的请求方式称为同步请求 同步请求 当网页与后端交互时,前端不能再进行其他操作 服务器端响应回来的内容,会把整个浏…...

(已开源-CVPR 2024)YOLO-World: Real-Time Open-Vocabulary Object Detection
169期《YOLO-World Real-Time Open-Vocabulary Object Detection》 You Only Look Once (YOLO) 系列检测模型是目前最常用的检测模型之一。然而,它们通常是在预先定义好的目标类别上进行训练,很大程度上限制了它们在开放场景中的可用性。为了解决这一限制…...

Spring6梳理4——SpringIoC容器
以上笔记来源: 尚硅谷Spring零基础入门到进阶,一套搞定spring6全套视频教程(源码级讲解)https://www.bilibili.com/video/BV1kR4y1b7Qc 目录 4.1 前言 4.2 IoC容器 4.2.1 控制反转(IoC) 4.2.2 依赖注入 4.2.3 IoC容器在Spri…...

SpringBoot2:请求处理原理分析-FORM表单请求接口
一、RESTFUL简介 Rest风格支持(使用HTTP请求方式,动词来表示对资源的操作) 以前:/getUser 获取用户 /deleteUser 删除用户 /editUser 修改用户 /saveUser 保存用户 现在: /user GET-获取用户 DELETE-删除用户 PUT-修改…...
Monkey日志ANR、CRASH、空指针异常及其他异常数据分析
引言 在Android开发过程中,monkey测试是一种常用的随机测试手段,用于模拟用户的各种操作来发现应用中的稳定性问题。通过monkey测试生成的日志文件包含了丰富的信息,包括应用程序崩溃(Crash)、无响应(ANR&…...
Vue 3结合Element Plus中,实现一个级联选择器(Cascader)来展示省市区
在Vue 3结合Element Plus中,实现一个级联选择器(Cascader)来展示省市区(甚至到更细分的级别,如街道、小区等)的联动选择是一个常见的需求。Element Plus的Cascader组件非常适合这样的场景,因为它…...

使用卫星仿真软件STK的一些应用和思考(星地链路、星间链路)
目录 任务描述利用STK建模星地协同系统3个GEO高轨卫星240/20/1 Walker-Star Constellation 低轨卫星星座地面站或者地面设备 链路建模与数据提取处理星地链路星间链路数据读取的几种方法最麻烦的方法使用Matlab与STK互联接口使用大规模使用Chain 总结 任务描述 在一个星地协同…...
pytorch对不同的可调参数,分配不同的学习率
在 PyTorch 中,你可以通过为优化器传递不同的学习率来针对不同的可调参数分配不同的学习率。这通常通过向优化器传递一个字典列表来实现,其中每个字典指定特定参数组的学习率。下面是一个示例代码,展示了如何实现这一点: import …...

零基础学习Python(八)—— time模块、request模块、数据分析和自动化办公相关模块、jieba模块、文件操作和os相关模块的简单介绍
1. time模块 time():获取当前时间戳,是一个数字 localtime():返回一个time.struct_time对象,里面有年月日时分秒,还有星期几(0表示星期一)和今年的第几天 import timeprint(time.time()) pri…...
快速回顾-HTML5
HTML5-常用的标签:https://blog.csdn.net/TKOP_/article/details/111395865 <!-- HTML5:声明文档类型的标签 --> <!DOCTYPE html><!-- 用于声明网页的主要语言为简体中文 --> <!-- 帮助搜索引擎、浏览器等理解网页的语言内容,以便…...

视频技术未来展望:EasyCVR如何引领汇聚融合平台新趋势
随着科技的飞速发展,视频技术已成为现代社会不可或缺的一部分,广泛应用于安防监控、娱乐传播、在线教育、电商直播等多个领域。本文将探讨视频技术的未来发展趋势,并深入分析TSINGSEE青犀EasyCVR视频汇聚融合平台的技术优势,展现其…...

7个流行的开源数据治理工具
数字化时代,数据是已经成为最宝贵的资产之一。数据支撑着我们的政府、企业以及各类组织的所有流程,并为决策以及智能化服务提供支撑。大数据有大用途,但是也可能隐藏着巨大的风险,特别是如果我们对数据的情况不是很了解的时候&…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...

EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...

【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...