RCU安全引用计数
原文网址:https://lwn.net/Articles/93617
原文作者:Corbet
原文时间:2004年7月14日
内核提供了一种用于实现引用计数的简单机制kref;该机制是今年3月份完成的。kref机制的核心思想是,提供支持原子操作的计数器,用于对未决引用【outstanding references】进行计数。如果计数器数值为零,内核不再需要引用对象了,引用对象可以被释放掉。
kref机制的函数很简单,在引用对象数据结构内直接包含一个struct kref计数器或struct kref *计数器指针,在引用对象被操作之前调用kref_get函数,引用计数器递增。
struct kref *kref_get(struct kref *kref)
{WARN_ON(!atomic_read(&kref->refcount));atomic_inc(&kref->refcount);return kref;
}
在对对象操作完成之后调用kref_put函数,引用计数器递减,如果计数器数值为零,就调用回调函数释放引用对象相关资源。
void kref_put(struct kref *kref)
{if (atomic_dec_and_test(&kref->refcount)) {kref->release(kref); //release函数是回调函数}
}
对引用计数refcount域进行原子操作,使得上述两个函数可以安全地在多CPU或抢断环境下直接调用,也就是说在这两个环境下,引用计数器的数值总能获得正确的结果。但是,如果两个内核线程在使用kref机制时,存在下面情况,kref机制也会出错。
| 内核线程1 | 内核线程2 |
/* In kref_get() */ WARN_ON(!atomic_read(&kref->refcount)); | |
kref_put(&kref); | |
atomic_inc(&kref->refcount); return kref; |
在上面的例子中,内核线程1在调用atomic_inc之前的那一刻,被引用对象的相关资源很可能被释放掉了。kref代码强制要求:对同一个引用对象不允许kref_get和kref_put并行运行。也就是说,这种强制性要求上述两个函数都需要用锁来避免对同一个引用对象的并行访问。
但是关注高可扩展性的程序员经常会使用免锁算法。因为在线程数量比较大的时候,锁往往会成为性能瓶颈,因此尽可能不用锁,内核的可扩展性会更好。这也是内核提供seqlock和RCU这两种技术的原因。kref机制对锁机制的需求,使得seqlock和RCU很难派上用途。
Ravikiran G Thirumalai最近提交了一份题为“Refcounting of objects part of a lockfree collection”的补丁,实现了一个新的锁机制refcount_t,用于对象的免锁管理。并用大量篇幅介绍了和RCU一起工作时引用计数过程,所有补丁构建了一种类似kref的数据类型,这种数据类型不需要用锁就能避免前面提到的竞争问题。
伴随并行写的过程【as currently written】,kref_get首先检查引用计数数值;如果计数数值为零,表示对象已经被释放了。当前的实现是,检查到数值为零时,仅仅是抱怨一下【我理解为信息输出,而不做更多的处理】;有人可能要说了,这种情况下应该做进一步的处理才好。然而,真正的问题是,对引用计数的测试和递增如果不能在一个原子操作中实现,那么在这两个操作之间就有可能插入其他操作。Ravikiran的补丁通过提供另一个XXXX_get函数来解决这个问题:
static inline int refcount_get_rcu(refcount_t *rc){int c, old;c = atomic_read(&rc->count);while ( c && (old = cmpxchg(&rc->count.counter, c, c+1)) != c) c = old;return c;}
上面函数的核心是cmpxchg函数,这是一个内联汇编函数,可以直接使用CPU的cmpxchg指令。这个函数的原型是:
int cmpxchg(int *location, int old, int new);
cmpxchg函数实现了以下基本功能:
1)用原子操作实现:比较location内存单元数值和old变量数值;如果两者数值相等,将location内存单元设置为new变量数值。
2)如果上述原子操作成功,即判断两者数值相等后location内存单元被修改,cmpxchg函数返回old变量数值;如果上述原子操作不成功,cmpxchg返回location内存单元的数值。
cmpxchg指令是CPU提供的测试-设置原子指令。用cmpxchg实现的XXXX_get函数在不用锁的情况下就可以实现引用计数器的获取。
这里还是有点小问题。考虑一种情况:内核线程2对引用计数对象释放后又重新使用该对象,然后内核线程1才试图去获取引用计数。在这种情况下,内核线程1可能看到的是一个随机的引用计数,就误以为成功获取了引用计数。引入RCU机制,可以避免这种情况发生。引用对象的释放是通过RCU回调函数来实现;这样一来,引用对象就不会被真正释放直到每一个处理器都发生了调度。只要内核线程能通过指针找到引用对象,那么这个对象就一直存在,即使对象的引用计数数值为零。经过一个完整静默期,没有内核线程去访问这样的指针了,引用对象才会被安全地删除。
另一个潜在的问题是,并不是所有的体系结构都提供cmpxchg原子指令。针对这样的系统,Ravikiran用到了一个从未见过但相当巧妙的方案,用到了自旋锁的哈希数组;如果你们好奇就自己去看补丁好了。
这些努力都是值得的;这个技术已经用于文件描述符查找了,tiobench测试性能提高了13% ~ 21%。内核系统里还有类似kref API一样的对象,也有创建新的引用计数API。因此,补丁还可能会重写。
相关文章:
RCU安全引用计数
原文网址:https://lwn.net/Articles/93617 原文作者:Corbet 原文时间:2004年7月14日 内核提供了一种用于实现引用计数的简单机制kref;该机制是今年3月份完成的。kref机制的核心思想是,提供支持原子操作的计数器&…...
Linux 可重入、异步信号安全和线程安全
可重入函数 当一个被捕获的信号被一个进程处理时,进程执行的普通的指令序列会被一个信号处理器暂时地中断。它首先执行该信号处理程序中的指令。如果从信号处理程序返回(例如没有调用exit或longjmp),则继续执行在捕获到信号时进程…...
WPF中手写地图控件(3)——动态加载地图图片
瓦片增加一个Loading动画 可以查看我的另一个博客WPF中自定义Loading图 从中心扩散 进行从里到外的扩散,方向是上左下右。如下图所示 于是我们可以定义一个拥有坐标X跟Y的集合,他允许这个集合,内部使用枚举器的MoveNext自动排序…...
智慧充电桩物联网方案架构
智慧充电桩物联网采用“云-管-边-端”的边缘计算物联网架构,融合5G、AI、Wi-Fi 6等技术,实现充电基础设施由数字化向智能化演进。智慧充电桩物联网方案架构设计,如下图所示: 云端: 物联网平台具备广泛协议的南向接入…...
C语言基础之——操作符(上)
本篇文章,我们将展开讲解C语言中的各种常用操作符,帮助大家更容易的解决一些运算类问题。 这里提醒一下小伙伴们,本章知识会大量涉及到二进制序列,不清楚二进制序列的小伙伴,可以去阅读我的另一篇文章《数据在内存中的…...
手写链式调用
遇到一个有趣的题目,做个笔记 实现一个arrange函数,可以进行时间和工作调度 //[> …]表示调用函数后的打印内容 //arrange(‘William’).execute(); //> William is notified //arrange(‘William’).do(‘commit’).execute(); //>William …...
DETRs with Collaborative Hybrid Assignments Training论文笔记
Title:[DETRs with Collaborative Hybrid Assignments Training Code 文章目录 1. Motivation2. one to one VS one to many3. Method(1)Encoder feature learning(2)Decoder attention learning 1. Motivation 当前…...
慧程HiperM3系列工业物联网、MES平台
产品链接:慧程产品主页...
SHELL 基础 入门(三) Bash 快捷键 命令执行顺序,详解通配符
目录 Bash 常用快捷键 输入输出重定向 << 用法 输出重定向 命令执行顺序 ; 分号 && || 通配符 传统通配符 ? * [ ] [ - ] [ ^ ] 常用字符 强调 : { } 生成序列 Bash 常用快捷键 Ctrl A 把光…...
nvm安装使用教程
文章目录 下载配置安装最新稳定版 node安装指定版本查看版本切换版本删除版本 常见问题安装node后 显示拒绝访问的问题使用cnpm会报错的问题降低cnpm版本npm镜像 下载 NVM for Windows 下载地址:https://link.juejin.cn/?targethttps%3A%2F%2Fgithub.com%2Fcoreyb…...
【Android】JUnit和Espresso单元测试新手快速入门
引入依赖 android {defaultConfig {testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"}}dependencies {testImplementation junit:junit:4.13.2androidTestImplementation androidx.test.ext:junit:1.1.0androidTestImplementation androidx.tes…...
8.4 【C语言】通过指针引用字符串
8.4.1 字符串的引用方式 在C程序中,字符串是存放在字符数组中的。想引用一个字符串,可以用以下两种方法。 (1)用字符数组存放一个字符串,可以通过数组名和下标引用字符串中一个字符,也可以通过数组名和格…...
【广州华锐视点】AR配电所巡检系统:可视化巡检利器
随着科技的发展,人工智能、大数据等技术逐渐应用于各个领域,为人们的生活带来便利。在电力行业,AR(增强现实)技术的应用也日益广泛。AR配电所巡检系统作为一种新型的巡检方式,可以实现多种功能,提高巡检效率࿰…...
微服务中间件--http客户端Feign
http客户端Feign http客户端Feigna.Feign替代RestTemplateb.自定义Feign的配置c.Feign的性能优化d.Feign的最佳实践分析e.Feign实现最佳实践(方式二) http客户端Feign a.Feign替代RestTemplate 以前利用RestTemplate发起远程调用的代码: String url "http:…...
C语言学习系列-->【关于qsort函数的详解以及它的模拟实现】
文章目录 一、概述二、qsort函数参数介绍三、qsort实现排序3.1 qsort实现整型数组排序3.2 qsort实现结构体数组排序 四、模拟实现qsort函数 一、概述 对数组的元素进行排序 对数组中由 指向的元素进行排序,每个元素字节长,使用该函数确定顺序。 此函数使…...
Linux系统安全:NAT(SNAT、DNAT)
目录 一.NAT 二.SNAT 三.DNAT 一.NAT NAT: network address translation,支持PREROUTING,INPUT,OUTPUT,POSTROUTING四个链 请求报文:修改源/目标IP, 响应报文:修改源/目标IP,根据…...
【数据库】MySQL存储过程:提升数据库性能和操作效率的利器
在数据库管理系统中,存储过程是一种重要的数据库对象,它允许将一组复杂的SQL语句组合起来,形成一个独立的单元进行重复使用。存储过程可以极大地提高数据库的性能和操作效率,降低网络流量,减轻系统负载。本文将深入探讨…...
rust写一个多线程和协程的例子
当涉及到多线程和协程时,Rust提供了一些非常强大的工具,其中最常用的库之一是tokio,它用于异步编程和协程。下面我将为你展示一个简单的Rust程序,演示如何使用多线程和协程。 首先,你需要在你的项目的Cargo.toml文件中…...
react18+antd5.x(1):Notification组件的二次封装
antdesign已经给我们提供了很好的组件使用体验,但是我们还需要根据自己的项目业务进行更好的封装,减少我们的代码量,提升开发体验 效果展示 开起来和官网的使用没什么区别,但是我们在使用的时候,进行了二次封装,更利于我们进行开发 MyNotification.jsx,是我们的业务页面…...
jenkins运行pytest测试用例脚本报错:没有权限,无法写日志PermissionError:[Error 13]Permission denied
报错信息: PermissionError:[Error 13]Permission denied:‘/var/jenkins_home/workspace/deleverySystem/Delivery_System/out_files/logs/waimai_20230823.log’ 解决方法: 在jenkins容器内部输入 chmod -R 777 /var/jenkins_home/works…...
java rabbitmq实现消息协作
场景:数据下载采用rpa实现,数据服务采用java springboot实现,需要进行一键数据补录操作1、设置消息承载的通信队列,java 发送任务到rabbitmq和rpa端收到消息(neimeng_data_download)后,将下载结…...
OpenCV实战:用Python+SIFT+八点算法搞定双目视觉匹配(附完整代码)
OpenCV实战:PythonSIFT八点算法实现双目视觉精准匹配 在计算机视觉领域,立体匹配是一个经典而富有挑战性的问题。想象一下,当你用双眼观察世界时,大脑能自动计算出物体的距离——这正是双目视觉系统要模拟的过程。本文将带你用Pyt…...
B端拓客号码核验行业:痛点剖析、技术突围与发展思考氪迹科技法人 号码筛选系统,阶梯式价格
B端拓客的效率与质量,很大程度上取决于核心决策人触达的精准度,而企业法人、股东、董监高等群体的有效联系方式,正是打通这一环节的关键。作为拓客工作的前置基础性步骤,号码核验的质量直接关联拓客投入的回报效率,更是…...
【FastAPI 2.0流式AI响应核心机密】:3大异步协程调度陷阱、2处EventSource底层劫持点、1个未公开的StreamingResponse状态机设计缺陷
第一章:FastAPI 2.0流式AI响应的架构演进与设计哲学FastAPI 2.0 将流式响应能力从实验性支持提升为核心原语,其底层重构了 Starlette 的响应生命周期与事件循环集成机制,使 Server-Sent Events(SSE)、text/event-strea…...
从机器人ROS2到微服务gRPC:手把手教你用IDL定义跨语言通信的‘世界语’
从机器人ROS2到微服务gRPC:手把手教你用IDL定义跨语言通信的‘世界语’ 清晨的阳光透过实验室的玻璃窗洒进来,机械臂正在执行预设的轨迹动作,而云端的数据分析服务实时监控着它的能耗曲线。这个看似简单的场景背后,隐藏着一个复杂…...
如何在群晖NAS上部署百度网盘客户端:终极安装与配置指南
如何在群晖NAS上部署百度网盘客户端:终极安装与配置指南 【免费下载链接】synology-baiduNetdisk-package 项目地址: https://gitcode.com/gh_mirrors/sy/synology-baiduNetdisk-package 还在为群晖NAS与百度网盘之间的文件同步问题而烦恼吗?群晖…...
OpenClaw深度配置:Qwen3.5-9B模型参数调优指南
OpenClaw深度配置:Qwen3.5-9B模型参数调优指南 1. 为什么需要关注模型参数调优? 第一次用OpenClaw对接Qwen3.5-9B模型时,我遇到了一个奇怪现象:同样的"整理桌面截图并分类归档"任务,白天执行成功率能达到8…...
二分查找/二分答案
0.前言二分算法(Binary Search),也叫折半查找,是一种在有序数据集合中高效查找目标值的算法。它通过不断将查找范围缩小一半,快速定位目标,时间复杂度为 O(logn),远优于线性查找的 O(n)。1.原理…...
Petalinux-build --sdk卡在assimp?手动下载源码并集成到Yocto构建系统的完整指南
解决Petalinux构建SDK时assimp源码下载失败的深度实践指南 当你在Ubuntu 18.04环境下使用Vivado 2021.2进行Petalinux开发时,执行petalinux-build --sdk命令可能会意外卡在assimp组件上。这种问题通常源于网络连接不稳定导致构建系统无法自动下载第三方依赖库。本文…...
终极指南:Autoenv如何彻底解决团队开发环境配置难题
终极指南:Autoenv如何彻底解决团队开发环境配置难题 【免费下载链接】autoenv 项目地址: https://gitcode.com/gh_mirrors/aut/autoenv Autoenv是一款强大的目录环境管理工具,能够在您进入包含.env文件的目录时自动执行其中的环境配置࿰…...
