当前位置: 首页 > 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;御银股份、雄帝科技 驱动…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...