linux内核 同步方法

Linux内核同步方式:从原理到应用 Linux内核同步方式:从原理到应用在操作系统中,多个进程或线程之间访问某些共享资源时,为了保证数据的正确性和一致性,需要使用同步机制。Linux 内核也不例外,为了避免多个进程或线程同时访问某些共享资源而引发的数据竞争或死锁等问题,其采用了多种同步方式。本文将从原理和应用两方面详细介绍 Linux 内核的同步机制。 阅读详情

1.完成变量(相当于条件变量)

如果在内核中一个任务需要发出信息号通知另一任务发生了某个特定事件,利用完成变量(completion variable)是使两个任务得以同步的简单方法。

2.BLK(大内核锁)

一种用于完成Linux内核从最初的SMP向细粒度枷锁机制的过度的全局自旋锁。

3.顺序锁

2.6内核新引进的锁机制。它提供了一种很简单的机制,用于读写共享数据。其实现主要依靠一个序列计数器。典型的应用为jiffies(用于存储Linux机器启动到当前时的时间)。

4.禁止抢占

内核代码使用自旋锁标记非抢占区域。如果已给自旋锁被持有,内核便不能进行抢占。

 

自从各种任务不再顺序执行的那一天起,自从多道程序设计开始上线的那天,进程就戴上了脚镣。古老的操作系统的变体当然也接过了父亲的狼牙棒,信号量杯证明是一种有效的互斥方式,可是它却存在很多弊端。其实unix不喜欢混乱,因此unix创造了进程这个可被操纵系统内核强制管理的执行绪概念,unix几乎给了所有可以执行的东西一个进程上下文,然后管理这些进程,unix的进程管理是很强大的,可是总有管不了的,就是中断,中断处理机制被视为一个硬件的无序性和软件进程管理的有序性之间的协调接口,因此中断处理程序并不属于任何进程的上下文,因此在中断中就不能像在别的进程上下文可以请求信号量,因为中断处理中根本就没有地方放床导致任意进程上下文下没有地方睡眠。中断处理不能睡眠是不能在中断处理用信号量的原因,因此必须提供一个中断处理中的互斥方案,另外,即使在进程上下文,如果需要的信号量很多,那么势必会造成进程频繁睡眠/被唤醒,这样进程调度的开销就过大,因此自旋锁就出来了,不用睡眠,只是自旋,很简单,在内核中很高效。

可是自旋锁是个平均的权衡结果,没有考虑到数据的客观特殊类型以及操作类型,自旋锁太机制化了,没有一点策略,其实想想便知道,读请求根本就不用锁也就是不用互斥,而写才需要互斥,在这种特殊需求下,linux提出了读写锁的概念,而且实现的十分艺术,如果看看很多学生写的读写锁再看看linux内核实现的读写锁,你会认为学生们的作品就是垃圾,国产的教科书就是垃圾堆!我们欣赏一下这种艺术:

static inline int __raw_read_trylock(raw_rwlock_t *lock)

{

atomic_t *count = (atomic_t *)lock;

atomic_dec(count); //以小跨度递减读信号量

if (atomic_read(count) >= 0)

return 1;

atomic_inc(count);

return 0;

}

static inline int __raw_write_trylock(raw_rwlock_t *lock)

{

atomic_t *count = (atomic_t *)lock;

if (atomic_sub_and_test(RW_LOCK_BIAS, count)) //以大跨度递减写信号量

return 1;

atomic_add(RW_LOCK_BIAS, count);

return 0;

}

static inline void __raw_read_unlock(raw_rwlock_t *rw)

{

asm volatile(LOCK_PREFIX "incl %0" :"+m" (rw->lock) : : "memory");

}

static inline void __raw_write_unlock(raw_rwlock_t *rw)

{

asm volatile(LOCK_PREFIX "addl %1, %0" : "+m" (rw->lock) : "i" (RW_LOCK_BIAS) : "memory");

}

static inline void __raw_read_lock(raw_rwlock_t *rw)

{

asm volatile(LOCK_PREFIX " subl $1,(%0)/n/t"

"jns 1f/n"

"call __read_lock_failed/n/t"

"1:/n"

::LOCK_PTR_REG (rw) : "memory");

}

static inline void __raw_write_lock(raw_rwlock_t *rw)

{

asm volatile(LOCK_PREFIX " subl %1,(%0)/n/t"

"jz 1f/n"

"call __write_lock_failed/n/t"

"1:/n"

::LOCK_PTR_REG (rw), "i" (RW_LOCK_BIAS) : "memory");

}

就这么多吗?是的,就这么多!很简单,很对称,如果不看函数名和宏定义,你根本就看不出来哪个是读锁哪个是写锁,它们的形式是一样的,也没有队列,也没有复杂的数据结构,从本质上说,读写锁是用自旋锁的思想实现的,自旋锁就是不断判断一个数字的大小,如果小于0就说明得不到锁,如果为1就得到了锁,释放锁就是将锁设置为1就可以,近来又实现了ticket自旋锁,使得锁变得有序化了,照顾到了硬件缓存的缓存结果。自旋锁就是不断判断一个数的大小,不管谁想得到锁都要经过竞争,也就是自旋,得不到锁就是因为将那个数减1后,它小于0了,如果让它不小于0不就可以得到锁了吗?我们的需求是读之间可以随意,但是写之间必须互斥,另外读写之间也要互斥,而在自旋锁中,无论读写都要一样的动作,那么我们只需要将读写分开成为不同的动作就可以了,目的就是要体现出读和写的不对称性,先看看自旋锁的实现,只要请求锁都要将锁变量减去1,只要释放都要将锁设置为1,那么读写锁中我们将读和写减去的数设置为不同就可以了,设置写锁请求时要减去一个很大的数N,而读锁只需要减去1,只要大于0就可以得到锁,如果不是就忙等待,这样的话,如果初始化的时候将锁初始化为N,那么只要有一个读,那么所就是N-1,如果再读,就是N-2,仍然大于0,如果写,就是-2,小于0,忙等,等待两个读者释放了锁,就是0了,那么写可以进行,写完后释放锁,就是将锁加上N,于是锁恢复N,其实这个实现和信号量有点类似,不同的是等不到锁时不睡眠而是忙等,此实现给了读很多的N个可用信号量,因为对于读,信号量的跨度是1,而对于写,只有1个信号量,写的跨度是N,这可以说是信号量的升级版,一个信号量支持两个不同的跨度,不过在等待的意义上,它又像是自旋锁,总之,linux内核的实现很是艺术吧。

说完了读写锁,那么看看顺序锁,顺序锁更具有创意,它基于一个事实,在读写锁中,如果读的时候恰好有一个写者在写,那么读者就要忙等,忙等是因为害怕读到不一致的数据,反过来如果写者发现有读者在读,它也要忙等,忙等是因为怕读者读到不一致的数据,这种互相照顾必然会影响效率,不管怎样我们都可以赌一把,这种赌博需要很小的赌注就值得,没有必要每次读的时候都要请求锁,而是随时都可以读,一旦读到不一致的数据,那么大不了再读一次,这个设想应该是很不错的,读写随时进行,谁也不管谁,自己注点意就可以了,比如以写者为主,读者自己进行数据一致性的判断,这样效率会提高不少的。

分析到这里可以想到,有两个点要注意,一个就是读开始,一个就是读结束,这两个点将时间分为了三个部分,读前,读中,读后,读前写完成和读后写完成都不会影响读操作,那么只有三类写操作会污染读者读到的数据,一个就是写在读前开始在读中结束,一个是在读中开始在读中结束,一个是在读中开始,在读后结束,于是我们只需要监控写开始和写结束即可,按照最简单的数学原理,如果设定一个变量,在写开始和写结束时都对它递增,我们就可以知道写的状态,这个数只要是偶数就说明没有在写中或者相反,取决于初始设置,那么读的时候可以尽量等到没有在写中的时候进行,然后在读结束的时候判断这个变量,如果被增加了就说明开始了一次写已经结束或者开始了一次写还没有结束,总之我们的数据被污染了,那么就需要再读一次,即使再读一次也不能保证没有写进行,但是我们可以再赌一把,这实际上是一个循环。这个顺序锁最起码解放了写操作,写操作不必关心读的情况,对于读操作纯粹是赌博,但是读写锁对读操作是有好处的,因为大多数情况下只要没有写者,读者都可以随意,总而言之,顺序锁还是比读写锁好的。我们还是看一眼顺序锁吧:

static inline void write_sequnlock(seqlock_t *sl)

{

smp_wmb();

sl->sequence++; //递增一个数字

spin_unlock(&sl->lock);

}

static inline void write_seqlock(seqlock_t *sl)

{

spin_lock(&sl->lock);

++sl->sequence; //释放锁也一样要递增一个数字

smp_wmb();

}

static __always_inline unsigned read_seqbegin(const seqlock_t *sl)

{

unsigned ret;

repeat:

ret = sl->sequence; //在读之前,先取得这个数字

smp_rmb();

if (unlikely(ret & 1)) { //确保没有在写中

cpu_relax();

goto repeat;

}

return ret;

}

static __always_inline int read_seqretry(const seqlock_t *sl, unsigned start)

{

smp_rmb();

return (sl->sequence != start); //判断这个数字是否改变

}

最后一类锁就是经典的RCU锁,这个锁我就不说那么多了,前面写过两篇文章说明这个锁。RCU锁基本没有利用什么锁,可是除了真正的锁之外,其它的特性它都用到了,比如RCU用到的就是cpu调度的周期,因为RCU确信自己不会破坏自己,只有别人可能破坏自己,如果不想自己被破坏,那么就不让别人运行,于是传统的RCU锁就是禁用抢占,而最新的RCU锁允许了抢占,但是Rcu的机制保护着rcu应该保护的数据。

 

Python实战:用MOOTDX库轻松抓取股票分时数据并绘制专业图表(附完整代码) 本文详细介绍了如何使用Python的MOOTDX库获取股票分时数据,并通过Pandas进行数据清洗与VWAP计算,最后利用Matplotlib绘制包含价格线、均线和成交量的专业分时图。文章提供了从环境搭建、数据获取到可视化呈现的完整代码,帮助读者快速构建本地化的股票分时数据分析工具。 阅读详情

相关推荐

工业音频故障检测:从CNN到Transformer的技术演进

音频信号处理是工业设备预测性维护的核心技术之一,通过分析设备运行时产生的声波特征实现故障预警。传统方法依赖梅尔频率倒谱系数(MFCC)等手工特征,而深度学习技术尤其是Transformer架构,通过自注意力机制突破了CNN在跨频段特征提取上的局限。Audio Spectrogram Transformer(AST)等先进模型在工业场景中展现出91.2%的高召回率,显著优于传统方案。这种非接触式监测技术结合边缘计算优化,已成功应用于石油化工、电力能源等领域,实现提前72小时预测轴承故障,单项目可避免数百万元的

weixin_30467861的博客 326

顺序锁(seqlock)

顺序锁的引入 前面学习了spin_lock可以知道,spin_lock对于临界区是不做区分的。而读写锁是对临界区做读写区分,并且度进程进入临界区的几率比较大,因为写进程进入时需要等待读进程退出临界区。而有没有一种方法,可以保护写进程的优先权,使得写进程可以更快的获得锁? 答案是有的,就是顺序锁。 顺序锁的原理 顺序锁的设计思想是:对某一个共享数据读取的时候不加锁,写的时候加锁。同时为

半月旋空 6162

MaixCAM2 4K AI相机硬件解析与开发实战

嵌入式AI视觉开发中,边缘计算设备的选择直接影响项目落地效果。以NPU为核心的AI加速技术通过专用指令集优化,可在低功耗下实现10+TOPS算力,典型应用包括工业质检、智能门禁等实时场景。MaixCAM2作为新一代4K AI相机,搭载AX630 SoC芯片,其双核Cortex-A53与NPU的异构架构,在运行YOLOv11n模型时可达113FPS,显著优于传统方案。开发时需注意模型量化部署技巧,如INT8量化需500+张校准图片覆盖多光照条件,避免准确率下降。设备扩展性方面,PMOD接口支持热成像、ToF传

weixin_30819085的博客 690

Linux中的各种锁

自从各种任务不再顺序执行的那一天起,自从多道程序设计开始上线的那天,进程就戴上了脚镣。古老的操作系统的变体当然也接过了父亲的狼牙棒,信号量杯证明是一种有效的互斥方式,可是它却存在很多弊端。其实unix不喜欢混乱,因此unix创造了进程这个可被操纵系统内核强制管理的执行绪概念,unix几乎给了所有可以执行的东西一个进程上下文,然后管理这些进程,unix的进程管理是很强大的,可是总有管不了的,就是中断

TCP/IP 7383

Arduino+esp8266+blinker物联网开发

文章目录blinker点灯一.简介二.开发环境的搭建1.arduino的安装2.添加esp8266开发板3. blinker库的导入4.驱动的安装4.手机端安装app三.开发第一个点灯程序1.添加设备2.载入示例3.代码部分4.代码讲解5.程序烧写四.总结 blinker点灯 一.简介 为了加深为物联网知识的认识,今天就教大家如何用手机app来控制我们的开发板。我们的开发环境是以arduino I...

weixin_45631738的博客 3万+

verilog CORDIC对数运算

verilog CORDIC对数运算

m0_64355812的博客 1735

《Linux 内核设计与实现》10. 内核同步方法

在 Linux 上 atomic_t 整数类型都是 32 位,其中数据位为高 24 位,低 8 位嵌入了一个锁,因为 SPARC 体系结构对原子操作缺乏指令级支持,所以只能利用该锁来避免对原子类型数据的并发访问。down_read_trylock() 和 down_write_trylock() 方法,若成功获得了信号量锁,返回非0,若信号量锁被争用,则返回0,这与普通信号量情况相反,要小心。自旋锁不可递归:你试图得到一个你持有的锁,必须自旋等待,可是你处于自旋等待中,因此无法释放锁,导致给自己锁死了。

XiaoLing 一直摆烂哇! 683

5实践报告撰写

一 项目流程 明确标准 确定分析目标 寻找分析数据 清洗数据 描述性分析 诊断性分析 提出建议 撰写报告 二 确定分析目标 什么是你感兴趣的? 什么是你熟悉的? 什么是你擅长的? 1 电商零售行业 商品销量分析 价格分析 评价分析 ...... 2 自媒体行业 广告投放力度分析 广告投放回报分析 不同类型的产品分析 ...... 3 金融行业 股票价格分析 信贷业务违约分析 客户画像分析 ...... ...

waywardG的博客 2830

Linux[内核同步的方法]

linux内核同步的方法

qq_42495902的博客 384

RK+linux教程:RK3588 RGA硬件加速在YOLOv5图像预处理中的深度应用教程

摘要: 本教程深入解析了RK3588芯片的RGA硬件加速器在YOLOv5图像预处理中的应用。通过专用硬件设计,RGA支持图像缩放、边界填充等核心操作,结合零拷贝技术显著提升处理效率。重点分析了LetterBox算法的RGA实现,包括参数计算、边界填充和性能优化,并与传统CPU处理对比,展示了RGA在高分辨率图像处理中的优势。教程还提供了统一的预处理接口设计,便于在OpenCV与RGA方案间灵活切换,为RK3588平台的深度学习部署提供实用优化方案。

LXY_LOVE36的博客 974

一.镜头知识之焦点,焦距,有效焦距,前焦距,后焦距

由光学系统中镜片的最后一面到像面的距离。

AIoT深度探索者 | 嵌入式系统架构师 深耕物联网(IoT)与人工智能(AI)融合技术,聚焦​​边缘计算、图像开发、低功耗通信协议​​,致力于智能硬件,关注我获取最新技术文章信息与海量资源~ 5575

Linux内核同步方法

原子操作 自旋锁、读-写自旋锁 信号量:二值信号量、读-写信号量 互斥量 完成变量

瓦釜苑 673

Spark Catalog详解

旁边的实习生说:我想要用spark代码中对hive库中的内部表和外部表进行删除(包括数据),咋感觉网上搜了一圈都找不到解决方案啊,spark这么鸡肋吗?我:你应该静下心来好好把spark基础知识进行全面学习。实习生:难道spark有这功能,而我没有学习过?咋弄啊?我:学习一下Spark Catalog。实习生:啥是Catalog啊?Spark Catalog是Spark SQL中的一个元数据管理组件,它提供了一个集中化的存储和查询表、视图和函数的位置。

SunnyRivers 1814

Linux内核设计与实现 - 第10章 内核同步方法

【代码】Linux内核设计与实现 - 第10章 内核同步方法。

baron-周贺贺-代码改变世界ctw 584

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

[linux]内核同步的方法

内核同步介绍 概念: 内核同步重要的原因:linux支持多处理器,2.6引入了抢占式内核 临界区:指访问和操作共享数据的代码段 竞争条件:如果两个线程有可能处于同一临界区中同时运行 内核同步的方法: 1,原子变量 2,加锁 造成并发的原因: 1,linux支持多处理器 2,2.6引入了内核抢占 3,中断 4,内核线程睡眠使得调度程序调度另外一个进程 确定哪些数据不需要被访

知了112的专栏 1705

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Linux内核同步介绍和方法

Linux设备驱动中必须解决的一个问题是多个进程对共享资源的并发访问,并发访问会导致竞态,linux提供了多种解决竞态问题的方式,这些方式适合不同的应用场景。  Linux内核是多进程、多线程的操作系统,它提供了相当完整的内核同步方法。内核同步方法列表如下:中断屏蔽原子操作自旋锁读写自旋锁顺序锁信号量读写信号量BKL(大内核锁)Seq锁一、并发与竞态

wswifth的专栏 1017

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

linux内核同步方法

内核中提供了多种方法来防止竞争条件,理解了这些方法的使用场景有助于我们在编写内核代码时选用合适的同步方法, 从而即可保证代码中临界区的安全,同时也让性能的损失降到最低。 主要内容: 原子操作自旋锁读写自旋锁信号量读写信号量互斥体完成变量大内核锁顺序锁禁止抢占顺序和屏障总结   1. 原子操作 原子操作是由编译器来保证的,保证一个线程对数据的操作不会被其他线程打断

everysmile的专栏 923

Linux内核同步,进程,线程同步各种方法

Linux内核同步,进程,线程同步各种方法包括我自己在内,很多人对内核,进程,线程同步都不是很清楚,下面稍微总结一下:内核同步:主要是防止多核处理器同时访问修改某段代码,或者在对设备驱动程序进行临界区保护。主要有一下几种方式:1. Mutex(互斥)头文件:#include 初始化方法:DEFINE_MUTEX(name);或者void mutex_init(struct mutex *lock);使用方法:void mutex_lock (struct mutex *lock);Tries to lock

cainiao413的专栏 936

linux内核同步的方法,[转载]linux内核同步方法-锁的使用

前面介绍了同步的概念以及使用的场合。接下来要介绍的是我们为了实现内核的同步,linux里面所提供的一些方法,当然从另外一个角度我们也可以看出linux的系统实现相当的完备。开头大致的罗列一下我们系统里面的同步方法吧:1.原子操作2.位操作3.自选锁4.读写锁5.信号量6.完成变量7.Seq锁8.禁止抢占9.BKL大内核锁10.。。。。。上面我们列举了那么多,不知道你常用那些来完成你的代码。反正我常...

weixin_32683881的博客 145

Linux内核设计与实现---内核同步方法

内核同步方法1 原子操作原子整数操作原子位操作2 自旋锁其他针对自旋锁的操作自旋锁和下半部3 读-写自旋锁4 信号量创建和初始化信号量使用信号量5 读-写信号量6 自旋锁和信号量7 完成变量8 BKL9 禁止抢占10 顺序和屏障 1 原子操作 原子整数操作 原子位操作 2 自旋锁 其他针对自旋锁的操作 自旋锁和下半部 3 读-写自旋锁 4 信号量 创建和初始化信号量 使用信号量 5 读-写信号量 6 自旋锁和信号量 7 完成变量 8 BKL 9 禁止抢占 10 顺序和屏障 ...

qq_41683305的博客 2550

Linux退回原有内核的方法,Linux内核同步方法

一.为什么内核需要同步方法并发指的是多个执行单元同时,并行被执行,而并发的执行单元对共享资源(硬件资源和软件上的全局变量,静态变量等)的访问则很容易导致竞态。主要竞态发生如下:1.对称多处理器(SMP)多个CPUSMP是一种紧耦合,共享存储的系统模型,它的特点是多个CPU使用共同的系统总线,因此可访问共同的外设和存储器。2.单CPU内进程与抢占它的进程Linux2.6内核支持抢占调度,一个进程在内...

weixin_39528000的博客 300

《Linux内核设计与实现》读书笔记(十)- 内核同步方法

内核中提供了多种方法来防止竞争条件,理解了这些方法的使用场景有助于我们在编写内核代码时选用合适的同步方法, 从而即可保证代码中临界区的安全,同时也让性能的损失降到最低。 主要内容: 原子操作 自旋锁 读写自旋锁 信号量 读写信号量 互斥体 完成变量 大内核锁 顺序锁 禁止抢占 顺序和屏障 总结 1. 原子操作 原子操作是由编译器来保证的,保证一个线程对数据的操作不会被其他线程打断。 原子操作有2类: 原子整数操作,有32位和64位。头文件分别为<asm/atom.

hhd1988的专栏 111

Linux内核、线程、进程同步互斥方法及IPC方法的总结

前段实践在B站进行模拟面试时发现,自己对Linux中的同步互斥方法,以及IPC方法,没有很好的理解和总结过。因此,本笔记将总结这部分内容。

ObviouslyCheng的博客 1248

Linux 同步方法剖析-Linux 同步方法剖析内核原子,自旋锁和互斥锁

Linux 同步方法剖析-Linux 同步方法剖析内核原子,自旋锁和互斥锁 在学习 Linux® 的过程中,您也许接触过并发(concurrency)、临界段(critical section)和锁定,但是如何在内核中使用这些概念呢?本文讨论了 2.6 版内核中可用的锁定机制,包括原子运算符(atomic operator)、自旋锁(spinlock)、读/写锁(reader/wr

Augusdi的专栏 1556

《Linux设备驱动程序》(第三版) 第4章 内核同步方法

在Linux内核中,多个执行单元(如进程、线程、中断处理程序等)可能会同时访问共享资源。如果没有适当的同步机制,这些并发访问可能会导致数据不一致或程序逻辑错误。例如,一个进程正在修改共享变量,而另一个进程同时读取该变量,可能会读到未完成修改的值。因此,需要同步机制来确保共享资源在同一时间只能被一个执行单元安全地访问。

qq_40844444的博客 1101
上一篇: C 扩展关键字 typeof 解析
下一篇: Vim 插件使用大全
奔跑的码仔
奔跑的码仔 领域专家: 嵌入式与硬件开发技术领域 领域专家: 嵌入式与硬件开发技术领域
博客等级 码龄15年 2万+粉丝 191原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值