当前位置: 首页 > news >正文

第四十章 linux-并发解决方法五(顺序锁seqlock)

第四十章 linux-并发解决方法四(顺序锁seqlock)


文章目录

  • 第四十章 linux-并发解决方法四(顺序锁seqlock)


顺序锁的设计思想是,对某一共享数据读取时不加锁,写的时候加锁。为了保证读取的过程中不会因为写入名的出现导致该共享数据的更新,需要在读取者和写入者之间引入一整型变量,称为顺序值sequence。读取者在开始读取前读取该sequence,在读取后再重读该值,如果与之前读取到的值不一致,则说明本次读取作过程中发生了数据更新,读取操作无效,因此要求写入者在开始写入的时候要更新sequence的值。

typedef struct {struct seqcount seqcount;spinlock_t lock;
} seqlock_t;

无符号型整数sequence用来协调读取者与写入者的作spinlock变量lock在多个写入者之间做互斥使用。
程序中如果想静态定义一个seqlock并同时初始化,可以使用DEFINESE_QLOCK宏,该宏会定义一个seqlock_t型变量并初始化其sequence为0,lock为0:

#define __SEQLOCK_UNLOCKED(lockname)            \{                        \.seqcount = SEQCNT_ZERO(lockname),    \.lock =    __SPIN_LOCK_UNLOCKED(lockname)    \}
#define DEFINE_SEQLOCK(x) \seqlock_t x = __SEQLOCK_UNLOCKED(x)

如果要动态初始化一个seqlock变量,可以使用seqlock_init:

#define seqlock_init(x)                    
do {                        
seqcount_init(&(x)->seqcount);        
spin_lock_init(&(x)->lock);        
} while (0)

下面看看写入者在seqlock上的上锁操作write_seqlock:

static inline void write_seqlock(seqlock_t *sl)
{spin_lock(&sl->lock);write_seqcount_begin(&sl->seqcount);
}
static inline void write_seqcount_begin(seqcount_t *s)
{write_seqcount_begin_nested(s, 0);
}
static inline void write_seqcount_begin_nested(seqcount_t *s, int subclass)
{raw_write_seqcount_begin(s);seqcount_acquire(&s->dep_map, subclass, 0, _RET_IP_);
}
static inline void raw_write_seqcount_begin(seqcount_t *s)
{s->sequence++;smp_wmb();
}

写入者在对写之前需要先获得seqlock上的自旋锁lock,这说明在写入者之间必须保证互斥操作,如果某一写入者成功获得lock。那么需要史新sequence的值以便让其他写入者知道共享数据发生了更新。写入者与写入者之间并不需要sequence。

static inline void write_sequnlock(seqlock_t *sl)
{write_seqcount_end(&sl->seqcount);spin_unlock(&sl->lock);
}
static inline void write_seqcount_end(seqcount_t *s)
{seqcount_release(&s->dep_map, 1, _RET_IP_);raw_write_seqcount_end(s);
}
static inline void raw_write_seqcount_end(seqcount_t *s)
{smp_wmb();s->sequence++;
}

主要的工作是释放自旋锁lock,至于写入者对sequence的更新,主要是用来告诉读取者有数据更新发生,所以必须确保sequence的值在写入的前后发生变化。在此基础上sequence提供的另外一个信息是写入过程有没有结束,这是用sequence的最低位来完成的,如果sequence & 0为0表明写入过程己经结束,否则表明写入过程正在进行·接下来会在读取者的seqlock作数中看到sequence的这两种用途。
某一写入者可以使用write_tryseqlock来保证在无法获得lock时不让自己进入自旋状态(当然也就无法更新数据)而直接返回0,成功获得锁则返回1:

读取者在读取开始前需要先调用read_seqbegin函数,该函数主要用来返回读取开始之前的sequence值:

static inline unsigned read_seqbegin(const seqlock_t *sl)
{return read_seqcount_begin(&sl->seqcount);
}
static inline unsigned read_seqcount_begin(const seqcount_t *s)
{seqcount_lockdep_reader_access(s);return raw_read_seqcount_begin(s);
}
static inline unsigned raw_read_seqcount_begin(const seqcount_t *s)
{unsigned ret = __read_seqcount_begin(s);smp_rmb();return ret;
}

s

tatic inline unsigned __read_seqcount_begin(const seqcount_t *s)
{unsigned ret;repeat:ret = READ_ONCE(s->sequence);if (unlikely(ret & 1)) {cpu_relax();goto repeat;}return ret;
}

从函数的实现也可以看出,如果当前正好有写入者在进行写操作,那么该函数将不停循环直到写过程结束,前面曾提到sequence最低位的用途,这里正好是其实际使用的地方。另一方面,从读取者对写入过程结束的孤环等待可以看出,写入者的实际写入操作占用的时间不应太长。
内核还给读取者提供了一个read_seqretry函数,与read_seqbegin的返回值一起使用,来判定本次的读取操作是否有效:

static inline unsigned read_seqretry(const seqlock_t *sl, unsigned start)
{return read_seqcount_retry(&sl->seqcount, start);
}
static inline int read_seqcount_retry(const seqcount_t *s, unsigned start)
{smp_rmb();return __read_seqcount_retry(s, start);
}
static inline int __read_seqcount_retry(const seqcount_t *s, unsigned start)
{return unlikely(s->sequence != start);
}

函数的参数是读取者在读取操作之前调用read_seqbegin获得的初始值。如果本次读取无效(读取过程中发生了数据更新),那么readq返回1,否则返回0。下面分别给出写入者和读取者利用上面介绍的seqlock函数进行数据读/写协调的例子:

//定义一个全局的seqlock变量demo_seqlock
DEFINE_SEQLOCK(demo_seqlock);//对于写入者的代码
...
//实际写之前调用write_seqlock获取自旋锁,同时更新sequence的值
write_seqlock(&demo_seqlock);
//获得自旋锁之后调用do_write进行实际的写入操作
do_write();
//写入结束,调用write_sequnlock释放锁
write_sequnlock(&demo_seqlock);//对于读取者的代码
unsigned start;
do{//读操作前鲜活的sequence的值start,用以在读操作结束时判断数据是否发生更新//注意读操作无需获得锁start = read_seqbegin(&demo_seqlock);//调用do_read进行实际操作do_read();
}while(read_seqretry(&demo_seqlock,start));//如果数据有更新,再重新读取

如果考虑到中断安全的问题,可以使用读取者与写入者的对应版本:

void write_seqlock_irq(seqlock_t *sl)
void write_seqlock_bh(seqlock_t *sl)
write_seqlock_irqsave(lock, flags)
void read_seqlock_irq(seqlock_t *sl)
void read_seqlock_bh(seqlock_t *sl)
read_seqlock_irqsave(lock, flags

前面曾讨论过读取者与写入者自旋锁rwlock,对比这里的seqlock.会发现两者非常相似。不同之处在于seqlock在写的时候只与其他写入者互斥,而rwlock在写的时候与读取者和写入者都互斥·因此当要保护的资源很小很简单,会很频繁被访问并且写入操作很少发生且必须快速时,就可以使用seqlock。

相关文章:

第四十章 linux-并发解决方法五(顺序锁seqlock)

第四十章 linux-并发解决方法四(顺序锁seqlock) 文章目录第四十章 linux-并发解决方法四(顺序锁seqlock)顺序锁的设计思想是,对某一共享数据读取时不加锁,写的时候加锁。为了保证读取的过程中不会因为写入名…...

【SPSS】交叉设计方差分析和协方差分析详细操作教程(附案例实战)

🤵‍♂️ 个人主页:@艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞👍🏻 收藏 📂加关注+ 目录 方差分析概述 交叉设计方差分析...

playwright--核心概念和Selector定位

文章目录前言一、浏览器二、浏览器上下文三、页面和框架四、Selectors1、data-test-id selector2、CSS and XPath selector3、text 文本selector4、id定位selector5、Selector 组合定位五、内置Selector前言 Playwright提供了一组API可自动化操作Chromium,Firefox和…...

响应式操作实战案例

Project Reactor 框架 在Spring Boot 项目 Maven 中添加依赖管理。 <dependency><groupId>io.projectreactor</groupId><artifactId>reactor-core</artifactId> </dependency><dependency><groupId>io.projectreactor</g…...

NetApp AFF A900:针对任务关键型应用程序的解决方案

NetApp AFF A900&#xff1a;适用于数据中心的解决方案 AFF A 系列中的 AFF A900 高端 NVMe 闪存存储功能强大、安全可靠、具有故障恢复能力&#xff0c;提供您为任务关键型企业级应用程序提供动力并保持数据始终可用且安全所需的一切。 AFF A900&#xff1a;针对任务关键型应…...

使用Houdini输出四面体网格并输出tetgen格式

我们的目标是从houdini输出生成的四面体&#xff0c;希望是tetgen格式的。 众所周知&#xff0c;houdini是不能直接输出四面体的。 有三方案去解决&#xff1a; 输出点云ply文件&#xff0c;然后利用tetgen生成网格。输出Hounidi内置的.geo格式文件&#xff0c;然后写个脚本…...

组合预测 | MATLAB实现EMD-KPCA-LSTM、EMD-LSTM、LSTM多输入单输出回归预测对比

组合预测 | MATLAB实现EMD-KPCA-LSTM、EMD-LSTM、LSTM多输入单输出回归预测对比 目录 组合预测 | MATLAB实现EMD-KPCA-LSTM、EMD-LSTM、LSTM多输入单输出回归预测对比预测效果基本介绍模型描述程序设计参考资料预测效果 基本介绍 MATLAB实现EMD-KP...

【C语言】操作符详解总结(万字)

操作符详解1. 操作符分类2. 算术操作符3. 移位操作符3.1 整数的二进制是怎么形成的3.2 左移操作符3.3 右移操作符4. 位操作符5. 赋值操作符6. 单目操作符6.1 单目操作符介绍6.2 sizeof 和 数组7. 关系操作符8. 逻辑操作符9. 条件操作符9.1 练习19.2 练习210. 逗号表达式11. 下标…...

mac系统手册(帮助/说明)

文章目录1. mac自带的帮助文档2. Mac使用技巧&#xff08;提示&#xff09;2.1 聚焦搜索2.2 截图&#xff08;录制屏幕&#xff09;2.3 调出右键菜单2.4 快速查看2.5 翻译2.5.1 词典解释2.5.2 翻译&#xff08;字、词和句&#xff09;3. macOS使用手册3.1 在聚焦中进行计算和转…...

VLC播放器Demo(录像,截图等功能),Android播放器Demo可二次开发。

VLC播放器Demo&#xff08;录像&#xff0c;截图等功能&#xff09;&#xff0c;可二次开发。 GitHub地址:https://github.com/ILoveLin/VlcRecordPlayer GitHub地址:https://github.com/ILoveLin/VlcRecordPlayer GitHub地址:https://github.com/ILoveLin/VlcRecordPlayer …...

WeSpeaker支持C++部署链路

WeSpeaker正式更新C部署链路&#xff0c;推理引擎使用OnnxRuntime&#xff0c;支持从语音中提取Speaker Embedding信息&#xff0c;代码详见WeSpeaker/runtime[1]。 Libtorch和onnx的选择? Speaker Embedding提取任务流程简单&#xff0c;并且声纹模型&#xff08;如ResNet\E…...

window vscode编辑appsmith源码

前言 本来最开始用的idea打开wsl中的appsmith&#xff0c;卡得一批。最后没办法&#xff0c;用自己的电脑装成ubuntu server&#xff0c;然后vscode的远程开发对appsmith源码进行编辑。如果自己电脑内存16个G或者更大可能打开wsl中的估计会还好&#xff0c;我公司电脑只有8g所…...

操作系统面试题

操作系统一、简介篇1.解释一下什么是操作系统2.操作系统的主要功能3.软件访问硬件的几种方式4.操作系统的主要目的是什么5.为什么Linux系统下的应用程序不能直接在Windows下运行6.什么是用户态和内核态7.用户态和内核态如何切换8.什么是内核二、进程和线程篇1.多处理系统的优势…...

Kafka入门(七)

下面聊聊Kafka的配置参数&#xff0c;包括生产者的配置参数、Broker的配置参数、消费者的配置参数。 1、生产者配置参数 acks 该参数控制了生产者的消息发送确认机制&#xff0c;用于指定分区中必须有多少个副本成功接收到消息后生产者才会认为这条消息写入是成功的&#xff0c…...

微服务介绍

微服务 微服务架构发展 微服务这个概念最早是在2011年5月威尼斯的一个软件架构会议上讨论提出的&#xff0c;用于描述一些作为通用架构风格的设计原则&#xff1b;2012年3月在波兰举行的Degree Conference大会&#xff0c;james lewis做演讲&#xff0c;讨论了微服务一些原则…...

搭建SpringBoot多模块微服务项目脚手架(三)

搭建SpringBoot多模块微服务项目脚手架(三) 文章目录搭建SpringBoot多模块微服务项目脚手架(三)1.概述项目结构2.接口返回统一信息模板2.1.封装返回统一信息思路介绍2.2.封装json数据格式1.导入依赖2.封装code码3.封装json格式模板4.使用统一返回信息3.接口统一请求信息模板3.1…...

对vue3中reactive、toref、torefs、ref的详细理解

reactive&#xff1a;将平常的一个对象转换成响应式对象。所谓的响应式对象就是当页面点击修改此对象时&#xff0c;页面无需刷新而在页面上的其他地方有用到这个对象的地方会自动同步修改过来例如&#xff1a; <template><div class"container"><di…...

C++ Primer Plus 第6版 读书笔记(6) 第 6 章 分支语句和逻辑运算符

第 6 章 分支语句和逻辑运算符 C是在 C 语言基础上开发的一种集面向对象编程、泛型编程和过程化编程于一体的编程语言&#xff0c;是C语言的超集。本书是根据2003年的ISO/ANSI C标准编写的&#xff0c;通过大量短小精悍的程序详细而全面地阐述了 C的基本概念和技术&#xff0c;…...

Java Class 加密工具 ClassFinal

Jar包加密工具 ClassFinal介绍环境依赖使用说明下载加密命令行示例maven插件方式无密码模式机器绑定启动加密后的jar启动参数给密码不加密码参数直接启动1. 密码文件获取2. 交互输入参考资料介绍 ClassFinal 是一款 java class 文件安全加密工具&#xff0c;支持直接加密jar包…...

【蓝桥杯集训·每日一题】AcWing 3555. 二叉树

文章目录一、题目1、原题链接2、题目描述二、解题报告1、思路分析2、时间复杂度3、代码详解三、知识风暴最近公共祖先一、题目 1、原题链接 3555. 二叉树 2、题目描述 给定一个 n 个结点&#xff08;编号 1∼n&#xff09;构成的二叉树&#xff0c;其根结点为 1 号点。 进行 m…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕&#xff0c;#AI 监考一度冲上热搜。当AI深度融入高考&#xff0c;#时间同步 不再是辅助功能&#xff0c;而是决定AI监考系统成败的“生命线”。 AI亮相2025高考&#xff0c;40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕&#xff0c;江西、…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...