rcu链表综合实践
基础知识
rcu-read copy update的缩写。和读写锁起到相同的效果。据说牛逼一点。对于我们普通程序员,要先学会使用,再探究其内部原理。
链表的数据结构:
struct list_head {struct list_head *next, *prev;
};
还有一种:struct hlist_head,本文不做该链表的测试。
struct hlist_head {struct hlist_node *first;
};struct hlist_node {struct hlist_node *next, **pprev;
};
涉及的文件:include\linux\rculist.h
初始化链表:INIT_LIST_HEAD_RCU
/** INIT_LIST_HEAD_RCU - Initialize a list_head visible to RCU readers* @list: list to be initialized** You should instead use INIT_LIST_HEAD() for normal initialization and* cleanup tasks, when readers have no access to the list being initialized.* However, if the list being initialized is visible to readers, you* need to keep the compiler from being too mischievous.*/
static inline void INIT_LIST_HEAD_RCU(struct list_head *list)
{WRITE_ONCE(list->next, list);WRITE_ONCE(list->prev, list);
}
添加节点list_add_rcu(插入到头节点后面)
/*** list_add_rcu - add a new entry to rcu-protected list* @new: new entry to be added* @head: list head to add it after** Insert a new entry after the specified head.* This is good for implementing stacks.** The caller must take whatever precautions are necessary* (such as holding appropriate locks) to avoid racing* with another list-mutation primitive, such as list_add_rcu()* or list_del_rcu(), running on this same list.* However, it is perfectly legal to run concurrently with* the _rcu list-traversal primitives, such as* list_for_each_entry_rcu().*/
static inline void list_add_rcu(struct list_head *new, struct list_head *head)
{__list_add_rcu(new, head, head->next);
}
添加节点list_add_tail_rcu(插入到头节点前面,就是链尾)
/*** list_add_tail_rcu - add a new entry to rcu-protected list* @new: new entry to be added* @head: list head to add it before** Insert a new entry before the specified head.* This is useful for implementing queues.** The caller must take whatever precautions are necessary* (such as holding appropriate locks) to avoid racing* with another list-mutation primitive, such as list_add_tail_rcu()* or list_del_rcu(), running on this same list.* However, it is perfectly legal to run concurrently with* the _rcu list-traversal primitives, such as* list_for_each_entry_rcu().*/
static inline void list_add_tail_rcu(struct list_head *new,struct list_head *head)
{__list_add_rcu(new, head->prev, head);
}
删除节点list_del_rcu
/*** list_del_rcu - deletes entry from list without re-initialization* @entry: the element to delete from the list.** Note: list_empty() on entry does not return true after this,* the entry is in an undefined state. It is useful for RCU based* lockfree traversal.** In particular, it means that we can not poison the forward* pointers that may still be used for walking the list.** The caller must take whatever precautions are necessary* (such as holding appropriate locks) to avoid racing* with another list-mutation primitive, such as list_del_rcu()* or list_add_rcu(), running on this same list.* However, it is perfectly legal to run concurrently with* the _rcu list-traversal primitives, such as* list_for_each_entry_rcu().** Note that the caller is not permitted to immediately free* the newly deleted entry. Instead, either synchronize_rcu()* or call_rcu() must be used to defer freeing until an RCU* grace period has elapsed.*/
static inline void list_del_rcu(struct list_head *entry)
{__list_del_entry(entry);entry->prev = LIST_POISON2;
}
删除尾节点hlist_del_init_rcu
/*** hlist_del_init_rcu - deletes entry from hash list with re-initialization* @n: the element to delete from the hash list.** Note: list_unhashed() on the node return true after this. It is* useful for RCU based read lockfree traversal if the writer side* must know if the list entry is still hashed or already unhashed.** In particular, it means that we can not poison the forward pointers* that may still be used for walking the hash list and we can only* zero the pprev pointer so list_unhashed() will return true after* this.** The caller must take whatever precautions are necessary (such as* holding appropriate locks) to avoid racing with another* list-mutation primitive, such as hlist_add_head_rcu() or* hlist_del_rcu(), running on this same list. However, it is* perfectly legal to run concurrently with the _rcu list-traversal* primitives, such as hlist_for_each_entry_rcu().*/
static inline void hlist_del_init_rcu(struct hlist_node *n)
{if (!hlist_unhashed(n)) {__hlist_del(n);n->pprev = NULL;}
}
替换list_replace_rcu:
/*** list_replace_rcu - replace old entry by new one* @old : the element to be replaced* @new : the new element to insert** The @old entry will be replaced with the @new entry atomically.* Note: @old should not be empty.*/
static inline void list_replace_rcu(struct list_head *old,struct list_head *new)
{new->next = old->next;new->prev = old->prev;rcu_assign_pointer(list_next_rcu(new->prev), new);new->next->prev = new;old->prev = LIST_POISON2;
}
计算长度
判空:list_empty
链表尾空时,返回值为1:链表不空时返回0。
下面这段注释的大体含义就是,当你想用list_empty_rcu的时候,list_empty就足够满足需要了。
/** Why is there no list_empty_rcu()? Because list_empty() serves this* purpose. The list_empty() function fetches the RCU-protected pointer* and compares it to the address of the list head, but neither dereferences* this pointer itself nor provides this pointer to the caller. Therefore,* it is not necessary to use rcu_dereference(), so that list_empty() can* be used anywhere you would want to use a list_empty_rcu().*/
获取节点对应的数据:list_entry_rcu
/*** list_entry_rcu - get the struct for this entry* @ptr: the &struct list_head pointer.* @type: the type of the struct this is embedded in.* @member: the name of the list_head within the struct.** This primitive may safely run concurrently with the _rcu list-mutation* primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().*/
#define list_entry_rcu(ptr, type, member) \container_of(READ_ONCE(ptr), type, member)
遍历 list_for_each_entry_rcu:
/*** list_for_each_entry_rcu - iterate over rcu list of given type* @pos: the type * to use as a loop cursor.* @head: the head for your list.* @member: the name of the list_head within the struct.* @cond: optional lockdep expression if called from non-RCU protection.** This list-traversal primitive may safely run concurrently with* the _rcu list-mutation primitives such as list_add_rcu()* as long as the traversal is guarded by rcu_read_lock().*/
#define list_for_each_entry_rcu(pos, head, member, cond...) \for (__list_check_rcu(dummy, ## cond, 0), \pos = list_entry_rcu((head)->next, typeof(*pos), member); \&pos->member != (head); \pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
链表综合实验代码
测试内容包括添加、计算长度、遍历数据、删除节点、替换节点。最后在卸载函数中释放链表资源。
#include <linux/module.h>
#include <linux/init.h>
#include <linux/rculist.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>#define _DEBUG_INFO
#ifdef _DEBUG_INFO#define DEBUG_INFO(format,...) \printk(KERN_ERR"%s:%d -- "format"\n",\__func__,__LINE__,##__VA_ARGS__)
#else#define DEBUG_INFO(format,...)
#endifstruct rcu_private_data{struct list_head list;
};struct my_list_node{struct list_head node;int number;
};static int list_size(struct rcu_private_data *p){struct my_list_node *pos;struct list_head *head = &p->list;int count = 0;if(list_empty(&p->list)){DEBUG_INFO("list is empty");return 0;}else{DEBUG_INFO("list is not empty");}list_for_each_entry_rcu(pos,head,node){count++;}return count;
}//遍历链表
void show_list_nodes(struct rcu_private_data *p){struct my_list_node *pos;struct list_head *head = &p->list;if(list_empty(&p->list)){DEBUG_INFO("list is empty");return;}else{DEBUG_INFO("list is not empty");}list_for_each_entry_rcu(pos,head,node){DEBUG_INFO("pos->number = %d",pos->number);}
}//清空链表
void del_list_nodes(struct rcu_private_data *p){struct my_list_node *pos;struct list_head *head = &p->list;if(list_empty(&p->list)){DEBUG_INFO("list is empty");return;}else{DEBUG_INFO("list is not empty");}list_for_each_entry_rcu(pos,head,node){DEBUG_INFO("pos->number = %d\n",pos->number);vfree(pos);}
}struct rcu_private_data *prpd;static int __init ch02_init(void){int i = 0;static struct my_list_node * new[6];struct rcu_private_data *p = (struct rcu_private_data*)vmalloc(sizeof(struct rcu_private_data));prpd = p;INIT_LIST_HEAD_RCU(&p->list);DEBUG_INFO("list_empty(&p->list) = %d",list_empty(&p->list));for(i = 0;i < 5;i++){new[i] = (struct my_list_node*)vmalloc(sizeof(struct my_list_node));INIT_LIST_HEAD_RCU(&new[i]->node);new[i]->number = i;list_add_rcu(&new[i]->node,&p->list);}DEBUG_INFO("list_size = %d",list_size(p));//添加后的结果,应该是5 4 3 2 1//遍历链表:show_list_nodes(p);//删除链表节点 new[3];list_del_rcu(&new[3]->node);vfree(new[3]);DEBUG_INFO("list_size = %d",list_size(p));//遍历链表:show_list_nodes(p);//替换一个链表节点new[5] = (struct my_list_node*)vmalloc(sizeof(struct my_list_node));INIT_LIST_HEAD_RCU(&new[5]->node);new[5]->number = i;list_replace_rcu(&new[1]->node,&new[5]->node);vfree(new[1]);//遍历链表:show_list_nodes(p);DEBUG_INFO("init");return 0;
}static void __exit ch02_exit(void){del_list_nodes(prpd);vfree(prpd);DEBUG_INFO("exit");
}module_init(ch02_init);
module_exit(ch02_exit);
MODULE_LICENSE("GPL");
测试
加载模块
卸载模块
小结
相关文章:

rcu链表综合实践
基础知识 rcu-read copy update的缩写。和读写锁起到相同的效果。据说牛逼一点。对于我们普通程序员,要先学会使用,再探究其内部原理。 链表的数据结构: struct list_head {struct list_head *next, *prev; };还有一种:struct h…...
odoo16-python框架-动作
总结 1 模型和视图的 设计之美 view_ids, view_id,view_mode 最终目的都是为了生成views, 也就是视图. 模型是死的,像男人,一成不变 视图像女人,千变万化, 姿态万千 一阴一阳之谓道,设计之美又在这里得到了体现 2 所有的动作都可以通过web界面来配置 可以通过在"设…...

微信小程序——同一控件的点击与长按事件共存的解决方案
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...

selenium自动化-获取元素属性信息
在写自动化过程中我们会想验证自己的代码是否正确,比如登录之后,通过用户名或其他信息来证明你登录成功,或者点击链接后,是否会跳转新的页面。通过获取元素属性信息,可以解决我们的疑惑。 一、获取内容对象的内容信息 …...

LabVIEW开发小型减阻试验平台
LabVIEW开发小型减阻试验平台 湍流摩擦在粘性流体的阻力中起着重要作用,减少湍流摩擦是流体力学领域的热门话题之一。在油气管道的长距离流体输送中,泵站提供的几乎所有动力都用于克服流体的胫骨摩擦。在流体输送领域,船舶的蒙皮摩擦阻力占总…...

解决分类任务中数据倾斜问题
大家好,在处理文本分类任务时,基准测试流行的自然语言处理架构的性能是建立对可用选项的理解的重要步骤。在这里,本文将深入探讨与分类相关的最常见的挑战之一——数据倾斜。如果你曾经将机器学习(ML)应用于真实世界的…...

Vue3 word如何转成pdf代码实现
🙂博主:锅盖哒 🙂文章核心:word如何转换pdf 目录 1.前端部分 2.后端部分 在Vue 3中,前端无法直接将Word文档转换为PDF,因为Word文档的解析和PDF的生成通常需要在后端进行。但是,你可以通过Vu…...
fpga--流水灯
fpga流水灯的设计 思路:外部时钟频率50mhz,若要实现每隔0.5s闪烁一次,则使用内部计数器计数到24999999拉高一个周期电平,当电平被拉高的时候,进行LED灯电平的设置,每次检测到高电平,就进行一位…...

51单片机:数码管和矩阵按键
目录 一:动态数码管模块 1:介绍 2:共阴极和共阳极 A:共阴极 B:共阳极 C:转化表 3:74HC138译码器 4:74HC138译码器控制动态数码管 5:数码管显示完整代码 二:矩阵按键模块 1:介绍 2:原理图 3:矩阵按键代码 一:动态数码管模块 1:介绍 LED数码管:数码管是一种…...

Django + Xadmin 数据列表复选框显示为空,怎么修复这个问题?
问题描述: 解决方法: 后续发现的报错: 解决方案: 先根据报错信息定位到源代码: 在该文件顶部写入: from django.core import exceptions然后把: except models.FieldDoesNotExist修改为&…...

《向量数据库指南》——Milvus Cloud2.2.12 易用性,可视化,自动化大幅提升
Milvus Cloud又迎版本升级,三大新特性全力加持,易用性再上新台阶! 近期,Milvus Cloud上线了 2.2.12 版本,此次更新不仅一次性增加了支持 Restful API、召回原始向量、json_contains 函数这三大特性,还优化了 standalone 模式下的 CPU 使用、查询链路等性能,用一句话总…...

Python web实战 | 用 Flask 框架快速构建 Web 应用【实战】
概要 Python web 开发已经有了相当长的历史,从最早的 CGI 脚本到现在的全栈 Web 框架,现在已经成为了一种非常流行的方式。 Python 最早被用于 Web 开发是在 1995 年(90年代早期),当时使用 CGI 脚本编写动态 Web 页面…...

十、数据结构——链式队列
数据结构中的链式队列 目录 一、链式队列的定义 二、链式队列的实现 三、链式队列的基本操作 ①初始化 ②判空 ③入队 ④出队 ⑤获取长度 ⑥打印 四、循环队列的应用 五、总结 六、全部代码 七、结果 在数据结构中,队列(Queue)是一种常见…...

Improving Cross-Modal Retrieval with Set of Diverse Embeddings
框架图: Using Triplet Loss: Smooth-Chamfer similarity Using Log-Sum-Exp,...
物联网阀控水表计量准确度如何?
物联网阀控水表是一种新型的智能水表,它采用了先进的物联网技术,可以通过远程控制和监测水表的运行情况,实现更加精准的水量计量和费用结算。那么,物联网阀控水表的计量准确度如何呢?下面我们将从以下几个方面进行详细…...

【C语言数据结构】模拟·顺序表·总项目实现
💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …...
自然语言处理从入门到应用——LangChain:模型(Models)-[文本嵌入模型Ⅰ]
分类目录:《自然语言处理从入门到应用》总目录 本文将介绍如何在LangChain中使用Embedding类。Embedding类是一种与嵌入交互的类。有很多嵌入提供商,如:OpenAI、Cohere、Hugging Face等,这个类旨在为所有这些提供一个标准接口。 …...

使用Gradio构建生成式AI应用程序; Stability AI推出Stable Diffusion XL 1.0
🦉 AI新闻 🚀 Stability AI推出最先进的AI工具Stable Diffusion XL 1.0 摘要:Stability AI宣布推出Stable Diffusion XL 1.0,该版本是其迄今为止最先进的AI工具。Stable Diffusion XL 1.0提供更鲜艳、更准确的图片生成ÿ…...
Java 递归计算斐波那契数列指定位置上的数字
Java 递归计算斐波那契数列指定位置上的数字 一、原理二、代码实现三、运行结果 一、原理 斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多斐波那契(Leonardo Fibonacci)以兔子繁殖为…...

ai数字人透明屏的应用场景有哪些?
AI数字人透明屏的应用场景: 银行、保险、售楼处等接待场景:AI数字人透明屏可以作为接待员,提供详细的信息和导航,提高客户体验和服务效率。 商业街、购物中心等场所:AI数字人透明屏可以作为导购员,提供商品…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...