linux设备驱动中的并发控制

linux设备驱动中的并发控制——信号量 Linux是一个多任务操作系统,肯定会存在多个任务共同操作同一段内存或者设备的情况,多个任务甚至中断都能访问的资源叫做共享资源。在驱动开发中要注意对共享资源的保护,也就是要处理对共享资源的并发访问。 现在的 Linux 系统并发产生的原因很复杂,总结一下有下面几个主要原因: ①、多线程并发访问, Linux 是多任务(线程)的系统,所以多线程访问是最基本的原因。 ②、抢占式并发访问,从 2.6 版本内核开始, Linux 内核支持抢占,也就是说调度程序可以在任意时刻抢占正在运行的线程,从而运行其他的线程。 阅读详情
并发控制的概念

        当并发进程竞争使用同一资源时,它们之间就会发生冲突。如果操作系统将资源分配给其中的某一个进程使用,

另一个进程就必须等待,直到申请的资源可用时由操作系统分配给它。如果竞争某资源的进程太多,这些进程还必

须等待在一个队列中,如就绪队列、阻塞队列等。一种极端的情况是,被阻塞进程永久得不到申请的资源而死锁。

竞态发生的情况

----对称多处理器(SMP)的多个CPU

----单CPU内进程与抢占它的进程

----中断(硬中断、软中断、Tasklet、底半部)与进程之间

解决竞态问题的途径

----保证对共享资源的互斥访问,所谓互斥访问是指一个执行单元在访问共享资源的时候,

----其他的执行单元被禁止访问。

----访问共享资源的代码称为临界区,临界区需要被以某种互斥机制加以保护。

互斥机制

(1)中断屏蔽;(2)原子操作;(3)自旋锁;(4)信号量;(5)完成量;(6)互斥体


一、中断屏蔽

在中断屏蔽期间所有的中断都无法得到处理,因此长时间屏蔽中断是很危险的,有可能造成数据丢失乃至系统崩溃等后果。

----local_irq_disable()    //屏蔽中断

----/*临界区*/

----local_irq_enable()    //开中断

----这种方式并不能解决SMP多CPU引发的竞态

注:local_irq_disable()和local_irq_enable()只能禁止和使能本CPU内的中断.
local_irq_save(flags);//禁止中断并保存当前CPU的中断位信息
local_irq_restore(flags);//恢复中断
local_bh_disable();//禁止中断底半部
local_bh_disable();//恢复中断底半部


二、原子操作

在执行的过程中不会被别的代码路径所中断的操作,原子变量所保护的共享资源通常是一个简单的整数值。

1、整形原子操作
1)设置原子变量的值
void atomic_set(atomic_t *v,int i);//设置原子变量的值为i
atomic_t v=ATOMIC_INIT(0);//定义原子变量V并初始化为0
2)获取原子变量的值
atomic_read(atomic_t *v);//返回原子变量的值
3)原子变量的加/减
void atomic_add(int i,atomic_t *v);//原子变量加i
void atomic_sub(int i,atomic_t *v);//原子变量减i
4)原子变量自增/减
void atomic_inc(atomic_t *v);//原子变量增加1
void atomic_dec(atomic_t *v);//原子变量减1
5)操作并测试
int atomic_inc_and_test(atomic_t *v);//操作并测试是否为0
int atomic_dec_and_test(atomic_t *v);
int atomic_sub_and_test(int i,atomic_t *v);
6)操作并返回
int atomic_add_return(int i,atomic_t *v);
int atomic_sub_return(int i,atomic_t *v);
int atomic_inc_return(atomic_t *v);
int atomic_dec_return(atomic_t *v);

2、位原子操作
1)设置位
void set_bit(nr,void *addr);//将addr的第nr位设置为1
2)清楚位
void clear_bit(nr,void *addr);//将addr的第nr为设置为0
3)改变位
void change_bit(nr,void *addr);//将addr的第n位进行反置
4)测试位
test_bit(nr,void *addr);//返回addr的第nr位
5)测试并操作位
int test_and_set_bit(nr,void *addr);
int test_and_clear_bit(nr,void *addr);
int test_and_change_bit(nr,void *addr);


----实现方法:

----头文件asm/atomic.h

----atomic_t  v=ATOMIC_INIT(1);         //定义原子变量v并初始化为1

----if(! atomic_dec_and_test(v))           //自减1测试

----{ atomic_inc(&v);  return –EBUSY; }  //设备忙返回错误码

----/*临界区*/                                //临界区代码

----atomic_inc(&c);                     //释放设备

三、自旋锁

如果进程A首先进入临界区,他将拥有自旋锁,当进程B试图进入同一临界区时,获知自旋锁已被持有,则在原地“自旋”,

等待进程A执行单元释放自旋锁后再进入临界区。

1、定义自旋锁
spinlock_t lock;
2、初始化自旋锁
spin_lock_init(lock);
3、获取自旋锁
spin_lock(lock);
spin_trylock(lock);//尝试获得自旋锁,如不能获得立即返回
4、释放自旋锁
spin_unlock(lock);


----实现方法:

----spinlock_t  lock;           //定义自旋锁

----spin_lock_init(&lock);  //初始化自旋锁

----spin_lock(&lock);        //获得自旋锁

---- /*临界区*/                   //临界区代码

----spin_unlock(&lock);    //释放自旋锁

一个例子:

static int cdev_open(struct inode*inode, struct file *file)

{

         spin_lock(&lock);

         if(flag== 1){

                   flag--;

                   spin_unlock(&lock);

                   printk(KERN_INFO"cdev_open !\n");      //临界区代码

                   return0;

         }else{

                   spin_unlock(&lock);

                   return-EBUSY;

         }

         return0;

}

static int cdev_release(struct inode*inode, struct file *file)

{

         flag++;

return 0;

}

----说明:自旋锁是一种忙等待锁,中间不能有可引起睡眠的操作;临界区不能太长;自旋

----锁可用在中断上下文中

四、信号量

信号量与自旋锁相同,只有得到信号量的进程才能执行临界区代码,但与自旋锁不同的是,获取不到信号量时,

进程不会原地“自旋”,而是进入休眠等待状态。

1、定义信号量
struct semaphore sem;
2、初始化信号量
void sem_init(struct semaphore *sem,int val);
3、获得信号量
void down(struct semaphore *sem);
int down_interruptible(struct semaphore *sem);//可被信号打断
int down_trylock(struct semaphore *sem);
4、释放信号量
void up(struct semaphore *sem);
5、信号量的使用
DECLARE_MUTEX(sem);
down(&sem);//获得信号量
...//临界操作
up(&sem);

----实现方法:

----struct semaphore  sem;         //定义信号量

----sema_init(&sem,1);               //初始化信号量

----down_interruptible(&sem);    //获取信号量

----/*临界区*/                              //临界区代码

----up(&sem);                             //释放信号量

----说明:信号量不同于自旋锁,他是一种睡眠锁,不能用在中断上下文中。

一种简单的使用方法:

----if(down_trylock(&sem))   //尝试打开锁

----return  –EBUSY;           //设备忙

----/*临界区*/                       //临界区代码

----up(&sem);                    //释放打开的锁

只有当进程占用资源时间较长时,用信号量才是最好的选择;

当对所要保护的临界区的访问时间比较短时,用自旋锁是非常方便的,因为他节省进程切换消耗的时间。

信号量和自旋锁作为解决互斥问题的主要手段, 无论是单处理系统还是多处理系统, 它们都可以不需修改

代码就进行移植, 通过以上分析总结出选择信号量和自旋锁的三项原则:
1) 当锁不能被获取时, 信号量的开销是进程上下文切换时间 Tsw, 自旋锁的开销是临界区的执行时间 Tcs, 

     若Tcs较小, 选自旋锁, 否则选信号量;

2) 信号量所保护的临界区可以包含引起阻塞的代码, 而自旋锁不可以, 否则将会发生死锁;

3) 如果共享资源在中断或软中断情况下使用,则只能选自旋锁, 如果一定要使用信号量应使用down_trylock( ),

    不能获取就立即返回以避免阻塞。

注意信号量不同于自旋锁, 它不会关闭内核抢占, 所以持有信号量的代码可以被抢占。这意味着信号量不会对影响调度反应时间带来负面影响。

读写自旋锁和读写信号量分别是放宽了条件的自旋锁与信号量,它们允许多个进程对共享资源的并发读。

五、完成量

完成量用于同步机制,它用于一个执行单元等待另一个执行单元完成某事。

1、定义完成量
struct completion my_completion;
2、初始化完成量
init_completion(&my_completion);
3、等待完成量
void completion(struct completion *my_completion);
void completion_all(struct completion *my_completion);

----实现方法:

          进程A                                                          进程B

struct completionmy_completion;

init_completion(&my_completion);

         代码区域a

wait_for_completion(&my_completion)              代码区域c

         代码区域b                                                  complete(&my_completion); //唤醒完成量,进程A继续


六、互斥体
1、初始化互斥体
struct mutex my_mutex;
mutex_init(&my_mutex);
2、获取互斥体
void inline  mutex_lock(struct mutex *my_mutex);
int  mutex_lock_interuptible(struct mutex *my_mutex);
int  mutex_trylock(struct mutex *my_mutex);
3、释放互斥体
void  mutex_unlock(struct mutex *my_mutex);
----实现方法:
----struct mutex my_mutex;
----mutex_init(&my_mutex);
----mutex_lock(&my_mutex);
----/*临界区*/
----mutex_unlock(&my_mutex);

 

固态变压器SST 1.1 课程整体框架与学习路径 本课程围绕固态变压器(SST)全生命周期工程化流程设计,构建"规范要求-理论基础-设计方法-仿真验证-工程落地"的闭环学习体系,完整覆盖GB/T 40429-2021标准要求。课程分为基础认知、核心设计、合规验证、工程落地和前沿拓展五大模块,采用理论讲解与工程实践深度融合的教学路径,通过规范条款拆解、仿真预验证、硬件实现、试验检测等环节,培养学员从设计到落地的完整能力。课程强调标准合规性,每个设计环节均有明确规范约束,并提供标准化工程模板,确保学习成果可直接应用于实际项目开发。 阅读详情

相关推荐

从零到一:手把手教你用SAM-BA工具完成嵌入式系统烧录

本文详细介绍了如何使用SAM-BA工具完成嵌入式系统烧录的全过程,包括环境搭建、硬件连接、Bootloader烧录以及完整系统镜像的烧录步骤。针对常见问题提供了实用的排查指南,并分享了批量烧录和自定义脚本的高级技巧,帮助开发者高效完成嵌入式系统开发。

weixin_42523792的博客 380

linux驱动mutex会阻塞,Linux内核崩溃mutex_lock_slowpath“阻塞超过120秒”.该怎么办?...

我有开箱即用的Debian Lenny非自定义内核2.6.26-2-amd64.全新的服务器,用于其潜力,cpu和磁盘方面的5%.意味着它可能不会因为过载而崩溃.每隔几天它就会在控制台日志中冻结数百条这样的消息:: [284847.828428] INFO: task apache2:12473 blocked for more than 120 seconds.: [284847.868468]...

weixin_30070961的博客 919

6.4 构网型储能的需求与配置

摘要: 构网型储能是新型电力系统的关键支撑技术,通过提供电压/频率形成、惯性和稳定控制能力,解决同步机退出导致的系统稳定性问题。其配置需遵循三大原则:1)容量配置以支撑需求为主导,兼顾能量服务;2)优先布局于电网薄弱点、稳定问题突出区域;3)采用自适应控制策略实现全工况优化。核心应用场景包括新能源送出通道稳定、负荷中心调频、黑启动电源等。规划方法需结合系统分析、量化指标和成本效益评估,实现技术经济最优。未来需重点关注构网/跟网混合系统的临界容量占比及自适应控制技术发展。

技术工作者 1140

学习笔记六:linux驱动之互斥锁mutex

互斥锁mutex 互斥体概述 信号量是在并行处理环境中对多个处理器访问某个公共资源进行保护的机制,mutex用于互斥操作。 mutex的语义相对于信号量要简单轻便一些,在锁争用激烈的测试场景下,mutex比信号量执行速度更快,可扩展性更好,另外mutex数据结构的定义比信号量小。 互斥锁使用注意事项: 1.同一时刻只有一个线程可以持有mutex。 2.只有锁持有者可以解锁,不能在一个进程中持有mutex,在另外一个进程中释放他。 3.不允许递归地加锁和解锁。 4.当进程持有mutex时,进程不可以退出。 5

weixin_45619852的博客 2128

Fedora 41上安装钉钉7.6.25,我踩过的那些依赖坑和最终解决方案

本文详细记录了在Fedora 41上安装钉钉7.6.25版本的全过程,包括解决依赖问题、转换deb包为rpm格式、处理libm.so.6错误等关键步骤。通过分享这些实用技巧和最终解决方案,帮助Linux用户顺利在Fedora系统上运行钉钉客户端,提升工作效率。

weixin_30485379的博客 206

抖音无人直播技术全解析:从原理、实操到合规化思考

直播技术作为内容分发的核心形式,其底层依赖于流媒体协议(如RTMP)与实时音视频编码推流。通过OBS等软件进行场景合成与虚拟摄像头技术,可以实现丰富的画面包装与自动化播放。这项技术的核心价值在于突破人力与时间的限制,实现内容的持续输出与流量获取,在电商带货、品牌展示、陪伴式内容等场景中具有应用潜力。然而,单纯依赖录播循环存在高风险,平台风控系统会通过内容重复性检测与互动行为模型进行识别。因此,更可持续的方向是探索“半无人直播”或自动化辅助工具,例如利用AI数字人驱动或直播切片技术,在合规前提下提升运营效率。

weixin_29895109的博客 508

linux驱动开发_互斥体

互斥体 与信号量只取0、1时有相同的表现形式。 相关代码 1.定义互斥结构体,并初始化 2.获取互斥体 mutex_lock () 与mutex_lock_interruptible () 的区别:前者引起的睡眠不能被信号打断,而后者可以。mutex_trylock ()用于尝试获得mutex,获取不到mutex时不会引起进程睡眠。 3.释放互斥体 完整使用案例: 互斥体是进程级的,用于多个进程之间对资源的互斥,虽然也是在内核中,但是该内核执行路径是以进程的身份,代表进程来争夺资源的。如果竞争失败

weixin_43625081的博客 343

OPPO 数据分析面试题及参考答案

如何设计共享单车数据库的各个字段? 对于共享单车的数据库设计,首先考虑用户相关的字段。用户表可以包含用户 ID,这是一个唯一标识符,用于区分不同用户;姓名,记录用户的真实姓名;联系方式,比如手机号码,方便在出现问题时联系用户;注册时间,记录用户何时开始使用共享单车服务;信用分数,用于衡量用户使用共享单车过程中的行为是否合规,比如是否按时归还车辆等。 车辆信息表要有车辆 ID,这是车辆的唯一标识;车辆类型,例如普通单车、电动单车等;投放时间,即车辆投放到市场的时间;车辆状态,包括是否可用(如正

大模型大数据攻城狮的专栏 1186

Linux设备驱动之互斥锁

Linux设备驱动之互斥锁 定义: 解决互斥问题的基本手段,互斥体是进程级的,用于多个进程之间对资源的互斥,虽然也是在内核中,但是该内核执行路径是以进程的身份,代表进程来争夺资源的。如果竞争失败,会发生进程上下文切换,当前进程进入睡眠状态,CPU将运行其他进程。鉴于进程上下文切换的开销也很大,因此,只有当进程占用资源时间较长时,用互斥体才是较好的选择。 初始化: struct mutex my_m...

weixin_43583605的博客 696

YOLO11改进大全:卷积层、轻量化、注意力机制、损失函数、Backbone、SPPF、Neck、检测头全方位优化汇总

YOLOv11改进大全:卷积层、轻量化、注意力机制、损失函数、Backbone、SPPF、Neck、检测头全方位优化汇总

魔改工程师的博客 4516

斑鬣狗优化算法(SHO)详解:从生物原理到代码实战

斑鬣狗优化算法(SHO)是一种新型元启发式优化算法,灵感来源于斑鬣狗的群体狩猎行为。该算法通过模拟斑鬣狗的包围猎物、协同狩猎和攻击猎物等生物行为,将优化问题转化为智能搜索过程。SHO算法包含探索与开发两个阶段,通过数学模型实现群体协作和自适应平衡,具有参数简单、收敛快等优势。文章系统介绍了SHO的生物基础、数学模型、实现方法(包括MATLAB和Python代码)、改进策略以及在函数优化、路径规划等领域的应用案例,最后讨论了算法的优势、局限性和未来研究方向。

qq_42212808的博客 237

驱动学习(七)驱动互斥

一类设备对应一个驱动程序,一类设备可以有多个子设备,当多个子设备同时访问一个驱动程序时,会造成竞态。简单来说就是厕所只有一个,不可以同时上。

a834605978的博客 573

【AN7581】AN7581 SDK编译环境搭建操作说明

安装编译需要的工具包。

wgl307293845的博客 338

Linux设备驱动中的并发控制

假设有一个链表,当然其中有数据,如果要修改其中的数据,自旋锁的思路就是排他性的去修改数据,而RCU的思路是,直接创建一个新的节点,然后原来的节点的内容复制到新节点上,再在新节点上修改数据,最后用新的节点去替代原来的节点,最后等待所有的CPU读完数据之后再去释放原来的节点。读写自旋锁方便的是读的操作,因为普通的自旋锁不关心是读还是写,一视同仁某一时刻只能允许一个执行单元对共享资源进行操作,而读写锁可以允许读的并发操作,但对写只能保持一个执行单元操作共享资源,当然读和写不能同时发生。

weixin_45241469的博客 1323

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

WINCC7.3破解文件

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

Linux驱动操作基石:(1)Linux设备驱动中的并发控制

并发与竞态: 并发指的是多个执行单元同时并行被执行,而并发的执行单元之间共享资源(硬件资源和软件上的全局变量、静态变量)的访问容易导致竞态。主要发生的场景有以下几种:编译乱序:执行乱序:解决方法:在单CPU范围内避免竞态的一种简单且有效的方式在临界区之前屏蔽系统的中断,但在驱动程序中不推荐使用。使用方法: 原子操作 定义:应用场景:常见的原子操作:实现机制:优点:限制:示例: 自旋锁 自旋锁是一种同步机制,用于保护共享资源,确保在同一时间只有一个线程可以访问这些资源。与互斥锁(如信号量)不同,自旋锁在等

2301_76151015的博客 1232

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Linux设备驱动中的阻塞与非阻塞IO与并发控制

Linux设备驱动中的阻塞与非阻塞IO: 1.Linux设备驱动中的阻塞与非阻塞总结:http://m.blog.youkuaiyun.com/blog/dongteen/17264501 2.Linux设备驱动中的阻塞与非阻塞IO:http://m.blog.youkuaiyun.com/blog/dongteen/17264501 3.Linux设备驱动中的阻塞与非阻塞I/O实例

借你一秒 1497

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

linux设备驱动中的并发控制-3

学习目的:学习linux设备驱动中的并发控制 编程练习:在globalmem字符设备基础上增加信号量管理共享资源 意外收获:第一次比着书上代码抄,很多东西理解不了,尤其file_operation什么时候调用,虽然现在也不懂。。。但好歹有个大致猜测理解 1- linux并发控制理解 学过ucos,很多和Linux相通。并发控制就是对共享资源的互斥访问。比如有一把手枪,你我都能想玩,但同一时...

u010743406的博客 275

Linux设备驱动中的并发控制总结

Linux设备驱动中的并发控制总结   并发(concurrency)指的是多个执行单元同时、并行被执行。而并发的执行单元对共享资源(硬件资源和软件上的全局、静态变量)的访问则容易导致竞态(race conditions)。    SMP是一种紧耦合、共享存储的系统模型,它的特点是多个CPU使用共同的系统总线,因此可访问共同的外设和存储器。    进程与抢占它的进程访问共

u010425035的专栏 575

【Linux】【并发】设备驱动中的并发控制

原子操作是指在一个操作中不可被中断的部分。在Linux内核中,原子操作通常用来更新共享变量而不必担心被其他任务打断。

极客代码 1395

Linux设备驱动中的并发控制(一)

在Linux设备驱动中必须解决的一个问题是,并发的访问会导致竞态,即使是经验丰富的驱动工程师也会常常设计出包含并发问题bug的驱动程序。Linux提供了多种解决竞态问题的方式,这些方式适合不同的应用场景。一起了解一下。

叫好与叫座虽然不是对立面,但想在同一个作品中达到双重效果很难。 527

20150518 Linux设备驱动中的并发控制

20150518 Linux设备驱动中的并发控制 2015-05-18 Lover雪儿 总结一下并发控制的相关知识: 本文参考:华清远见《Linux 设备驱动开发详解》—第7章 Linux 设备驱动中的并发控制,更多详细内容请看原书 一、并发与竞态 并发(concurrency)指的是多个执行单元同时、并行被执行,而并发的执行单元对共享资源(硬件资源和软件上的全局变量、静态变量等)的访问...

|~~~热爱生活、努力学习的小伙汁~~~| 569
上一篇: TCP三次握手及四次挥手详细图解
下一篇: linux 内存与I/O访问机制
小飞鱼hubble
博客等级 码龄15年 14粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值