[特殊字符]‍[特殊字符]Linux驱动开发入门 | 并发与互斥机制详解

文章目录

  • 👨‍💻Linux驱动开发入门 | 并发与互斥机制详解
    • 📌为什么驱动中需要并发和互斥控制?
    • 💡常见的并发控制机制
    • 🔐自旋锁和信号量通俗理解
      • 🌀自旋锁(Spinlock)——“厕所排队锁”
      • 🚦信号量(Semaphore)——“停车场智能显示器”
    • 🆚 自旋锁 vs 信号量
    • 读写锁是什么?
    • 🚨死锁问题和解决策略
      • 一、预防死锁
        • 1. 资源一次性分配(破坏请求与保持条件)
        • 2. 可剥夺资源(破坏不可剥夺条件)
        • 3. 资源有序分配法(破坏循环等待条件)
      • 二、避免死锁
        • 银行家算法
      • 三、死锁检测
        • 步骤如下:
      • 四、解除死锁
        • 1. 剥夺资源
        • 2. 撤消进程
      • 五、避免死锁的编程实践
        • 1. 加锁顺序(Lock Ordering)
        • 2. 加锁时限(Try Lock with Timeout)
        • 3. 死锁检测机制
      • 总结
    • 🧪真实驱动例子:互斥访问设备寄存器
      • 临界区:
    • 🧠Q&A 常见问题
    • ✅总结

👨‍💻Linux驱动开发入门 | 并发与互斥机制详解

📌为什么驱动中需要并发和互斥控制?

我们知道,在多线程或多任务并行执行的操作系统中,比如Linux内核,多个执行单元(线程或中断)可能同时访问共享资源(如全局变量、设备寄存器、缓冲区等),这就带来了“竞态条件(Race Condition)”的风险。

举个简单的例子:
假如两个线程A和B几乎在同一时间读取同一个计数变量x的值为10,然后各自+1并写回。你期望x变为12,但结果可能还是11。

这类问题就需要“互斥”机制来保护——确保同一时刻只能有一个执行单元访问共享资源,其访问的代码区域称为临界区(Critical Section)


💡常见的并发控制机制

Linux驱动开发中,常见的互斥控制方式有以下几种:

互斥机制特点场景
中断屏蔽禁止中断上下文干扰适用于简单、快速完成的临界区
原子操作使用CPU原子指令保证变量操作完整操作变量极少时
自旋锁(spinlock)自旋等待,适合短时间锁定中断/进程上下文
信号量(semaphore)可睡眠等待,适合长时间持锁进程上下文,驱动任务中常用
互斥锁(mutex)是信号量的简化版本一般用于用户态/驱动模块

🔐自旋锁和信号量通俗理解

🌀自旋锁(Spinlock)——“厕所排队锁”

把共享资源想象成一个单人厕所。

  • 线程A进入厕所,并锁门(获取锁);
  • 线程B也想用厕所,只能在门口一直转圈圈(不停检查锁状态);
  • A出来后释放锁,B才能进去。

自旋锁适合锁定时间非常短的临界区,因为等待期间线程一直占用CPU,不睡觉!

✅ 优点:

  • 实时性好(适合中断上下文)
  • 实现简单

❌ 缺点:

  • CPU占用率高,锁持有久了会浪费资源
  • 不可在临界区使用可能睡眠的代码!

🚦信号量(Semaphore)——“停车场智能显示器”

假设一个停车场有100个车位,信号量就相当于入口处的电子屏:

  • 显示“当前车位:20”,车还能进;
  • 显示“满”,车就得等;
  • 有车离开,车位更新,通知其他等车入场。

信号量适合临界区操作时间较长、可能会阻塞的场景

✅ 优点:

  • 可睡眠等待,不占CPU
  • 适合处理资源池问题,如连接池、缓存池等

❌ 缺点:

  • 实时性差,不可用于中断处理
  • 实现复杂,需考虑死锁
  • 锁被短时间持有时,使用信号量就不太适宜了,因为睡眠引起的耗时可能比锁被占用的全部时间还要长。

🆚 自旋锁 vs 信号量

对比项自旋锁信号量
是否睡眠❌ 不可睡眠✅ 可睡眠等待
适用上下文中断上下文进程上下文
临界区时长极短可长
是否允许抢占❌ 不允许(禁抢)✅ 允许抢占
用于中断中✅ 可以❌ 禁止
是否可重入❌ 否✅ 是(看实现)

在你占用信号量的同时不能占用自旋锁,因为在你等待信号量时可能会睡眠,而在持有自旋锁时是不允许睡眠的。


读写锁是什么?

当临界区的一个文件可以被同时读取,但是并不能被同时读和写。如果一个线程在读,另一个线程在写,那么很可能会读取到错误的不完整的数据。读写自旋锁是可以允许对临界区的共享资源进行并发读操作的。但是并不允许多个线程并发读写操作

🚨死锁问题和解决策略

在操作系统或并发编程中,**死锁(Deadlock)**是一个经典问题。本文将带你由浅入深地了解死锁的处理方式,主要包括四种:预防死锁、避免死锁、检测死锁以及解除死锁。


一、预防死锁

死锁产生的四个必要条件是:互斥、不可剥夺、请求与保持、循环等待。

为了预防死锁,我们可以通过破坏其中一个或多个条件来避免死锁的发生。

1. 资源一次性分配(破坏请求与保持条件)

当一个进程申请资源时,必须一次性申请它执行所需的所有资源。如果一次申请不到,就什么也不分配,避免持有部分资源再申请其他资源。

2. 可剥夺资源(破坏不可剥夺条件)

允许系统在资源不足时,强行从某些进程中回收已分配的资源,重新分配给其他更需要的进程。

3. 资源有序分配法(破坏循环等待条件)

为所有资源编号,进程必须按编号递增的顺序申请资源。释放时则按编号递减顺序释放。这样可以避免资源请求形成闭环。


二、避免死锁

相比预防死锁,避免死锁不要求完全避免死锁条件的成立,而是在每次资源分配时判断是否安全。

银行家算法

预防死锁的几种策略,会严重地损害系统性能。因此在避免死锁时,要施加较弱的限制,从而获得较满意的系统性能。由于在避免死锁的策略中,允许进程动态地申请资源。因而,系统在进行资源分配之前预先计算资源分配的安全性。
这是最经典的死锁避免算法。

  • 系统在每次资源分配前,模拟本次资源分配是否会导致系统进入不安全状态。
  • 如果安全,则分配资源;否则让进程等待。

三、死锁检测

死锁检测是允许死锁发生,但系统会定期检查是否有死锁存在,一旦检测到就进行处理。

步骤如下:
  1. 系统记录所有进程与资源的指定一个唯一的号码,构建资源分配图或等待图。
  2. 检查是否存在环路(循环等待)结构。
  3. 若有环路,即可判定发生了死锁。

四、解除死锁

当检测到死锁后,需要采取措施解除死锁状态。常见方法如下:

1. 剥夺资源

从非死锁进程中剥夺资源分配给死锁进程,让后者能继续运行,释放资源。

2. 撤消进程
  • 终止死锁进程或一些代价较小的进程,释放资源。
  • 代价可以依据优先级、运行时间、完成率、业务重要性来评估。

五、避免死锁的编程实践

在多线程编程中(如Java、C++),我们还可以通过一些实际的编程技巧避免死锁:

1. 加锁顺序(Lock Ordering)

确保所有线程在获取多个锁时,始终按照固定顺序获取。例如:线程要获取锁A和锁B,必须先获取编号小的锁A,再获取锁B。

// Thread 1:
synchronized(lockA) {synchronized(lockB) {// do something}
}
// Thread 2: 也必须先获取lockA,再获取lockB

按照顺序加锁是一种有效的死锁预防机制。但是,这种方式需要你事先知道所有可能会用到的锁,并对这些锁做适当的排序),但总有些时候是无法预知的。

2. 加锁时限(Try Lock with Timeout)

设置锁获取的超时时间,如果无法在一定时间内获取到锁,就放弃。

if(lock.tryLock(500, TimeUnit.MILLISECONDS)) {try {// do something} finally {lock.unlock();}
} else {// 获取锁失败,执行其他逻辑或重试
}

这种方式可以有效避免长时间等待。

3. 死锁检测机制

针对上面两种不适用的场景。那些不可能实现按序加锁并且锁超时也不可行的场景
使用数据结构记录线程和资源的持有与请求状态,在失败时主动检查是否形成了等待环。

当检测到环路时:

  • 某些线程主动释放锁虽然有回退和等待,但是如果有大量的线程竞争同一批锁,它们还是会重复地死锁,原因同超时类似,不能从根本上减轻竞争
  • 或者优先级较低的线程撤退一段时间再重试

这种方式适合无法提前安排加锁顺序的复杂应用场景。


总结

方法是否允许死锁发生是否易于实现是否影响性能
预防死锁较简单
避免死锁
死锁检测
解除死锁复杂低(只在死锁发生时影响)

🧪真实驱动例子:互斥访问设备寄存器

假设我们要编写一个字符设备驱动,多个进程可能并发调用 read() 操作,访问同一片寄存器区域。

临界区:

static DEFINE_SPINLOCK(my_lock);ssize_t my_read(struct file *file, char __user *buf, size_t len, loff_t *off) {unsigned long flags;spin_lock_irqsave(&my_lock, flags);// 临界区:访问共享寄存器data = ioread32(dev->reg_base);spin_unlock_irqrestore(&my_lock, flags);return 0;
}

注意:用 spin_lock_irqsave 是因为中断中也可能调用,必须禁止中断防止死锁!


🧠Q&A 常见问题

Q:单核CPU还需要加锁吗?
A:需要!因为即使单核,操作系统依然可以通过抢占调度让线程切换,导致共享变量被多个线程交叉访问。

Q:信号量可以用在中断中吗?
A:不能!因为信号量可能会休眠,而中断处理函数不能休眠,否则整个中断系统会挂死。

Q:spin_lock能不能睡眠?
A:不能!因为它禁止抢占,如果睡眠,系统可能无法调度其他任务,导致死锁。


✅总结

  • 多线程 + 共享资源 = 必须互斥
  • 自旋锁适合临界区非常短的场景;信号量适合长时间、可睡眠的场景
  • 死锁问题复杂,要尽量规避:统一加锁顺序、设置超时、图算法检测
  • 在驱动中使用锁时要特别考虑上下文(中断/进程)和是否可休眠

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/903109.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kafka 架构设计和组件介绍

什么是Apache Kafka? Apache Kafka 是一个强大的开源分布式事件流平台。它最初由 LinkedIn 开发,最初是一个消息队列,后来发展成为处理各种场景数据流的工具。 Kafka 的分布式系统架构支持水平扩展,使消费者能够按照自己的节奏检…

elk中kibana一直处于可用和降级之间且es群集状态并没有问题的解决方法

前言 在公司部elk的时候发现kibana的web界面一直很卡,数据量为0也会很卡,es群集状态正常,资源足够。 报错信息 [2025-03-17T09:54:50.19400:00][INFO ][status] Kibana is now available (was degraded) [2025-03-17T09:55:03.28000:00][I…

什么是视频上墙

视频联动上墙是指当监控系统中出现报警或其他特定事件时,相关的视频画面能够自动切换并显示在指定的监控大屏或显示设备上,以便监控人员能够快速、直观地查看事件现场的情况,及时做出响应和处理。 具体介绍• 系统组成 :一般由前端…

26考研——存储系统(3)

408答疑 文章目录 一、存储器概述二、主存储器三、主存储器与 CPU 的连接四、外部存储器五、高速缓冲存储器六、虚拟存储器七、参考资料鲍鱼科技课件26王道考研书 八、总结复习提示思考题常见问题和易混淆知识点 一、存储器概述 文章链接: 点击跳转 二、主存储器 文章链接: …

.NET 6 + Dapper + User-Defined Table Type

大家都知道,对于SQL Server IN是有限制条件的,如果IN里面的内容过多,在执行的时候会被自动截断,因而导致查询到的结果不是实际需要的结果。 select * from Payments where Id in (1,2,3,4,...) 为了解决上面的限制,可以…

MySQL 8(Ubuntu 18.04.6 LTS)安装笔记

一、前言 其实之前已经写过一篇笔记【MySQL 8.0.34(x64)安装笔记】。机缘巧合,这次遇到的环境是Ubuntu 18.04 LTS,相比Windows平台的安装,对mysql的版本以及依赖的选择,稍微要窄一些。特作笔记。 二、准备…

学习 Apache Kafka

学习 Apache Kafka 是一个很好的选择,尤其是在实时数据流处理和大数据领域。以下是一个系统化的学习建议,帮助你从入门到进阶掌握 Kafka: 1. 先决条件 在开始 Kafka 之前,确保你具备以下基础: Java 基础:K…

使用 binlog2sql 闪回 MySQL8 数据

【说明】 MySQL服务器版本 8.0.26 mysql> SELECT version(); ----------- | version() | ----------- | 8.0.26 | -----------Python 版本 Python 3.8.10 [infuq ~]# python -V Python 3.8.10【安装】 binlog2sql 官方地址 1.安装 binlog2sql [infuq ~]# git clone …

JavaScript 异步编程与请求取消全指南

JavaScript 异步编程与请求取消全指南 涵盖:同步/异步、Promise、async/await、AbortController、前后端协作 一、同步与异步 1. 同步(Synchronous) 定义:代码按顺序执行,前一步完成才能执行下一步。特点&#xff1…

永久缓存 Git 凭证

永久缓存 Git 凭证 打开终端或命令行工具。 执行以下命令,设置 Git 使用 store 凭证帮助程序: bash git config --global credential.helper store第一次执行 git pull 时输入账号密码。之后,所有需要凭证的操作都将自动使用存储的凭证&…

力扣-48.旋转图像

题目描述 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 class Solution { public:void rotate(vector<vector<int>…

Qt ModbusSlave多线程实践总结

最近项目中用到了ModbusSlave&#xff0c;也就是Modbus从设备的功能&#xff0c;之前用的基本都是master设备&#xff0c;所以读取数据啥的用单线程就行了&#xff0c;用 void WaitHelper::WaitImplByEventloop(int msec) {QEventLoop loop;QTimer::singleShot(msec, &loop…

opencv--图像

像素(像素点) 定义&#xff1a; Pixel 是 Picture Element&#xff08;图像元素&#xff09;的缩写&#xff0c;是数字图像中最小的独立单位。每个像素代表图像中的一个点的颜色和亮度信息。 关键特性&#xff1a; 颜色&#xff1a;通过不同的色彩模型&#xff08;如RGB、CMYK…

记录学习汇编语言02+各种寄存器分类

8086cpu是十六位的 然后寄存器能存八位 所以分为高八位低八位 高八位在下面低八位在上面 从下往上读&#xff08;从地址小的地方开始读&#xff09; 8086cpu种有两个和栈相关的寄存器 栈段寄存器ss&#xff08;栈顶的段寄存器&#xff09; 栈顶指针寄存器sp&#xff08;…

OpenCV 图形API(53)颜色空间转换-----将 RGB 图像转换为灰度图像函数RGB2Gray()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将图像从 RGB 色彩空间转换为灰度。 R、G 和 B 通道值的常规范围是 0 到 255。生成的灰度值计算方式如下&#xff1a; dst ( I ) 0.299 ∗ src…

(51单片机)LCD显示数据存储(DS1302时钟模块教学)(LCD1602教程)(独立按键教程)(延时函数教程)(I2C总线认识)(AT24C02认识)

目录 演示视频&#xff1a; 源代码 main.c LCD1602.c LCD1602.h AT24C02.c AT24C02.h Key.c Key.h I2C.c I2C.h Delay.c Delay.h 代码解析与教程&#xff1a; Dealy模块 LCD1602模块 Key模块 I2C总线模块 AT24C02模块 /E2PROM模块 main模块 演示视频&#xff1a; E2…

电子病历高质量语料库构建方法与架构项目(数据遗忘篇)

引言 在人工智能与医疗健康的深度融合时代,医疗数据的价值与风险并存。跨机构和平台的医疗数据共享对于推动医学研究、提高诊断精度和实现个性化治疗至关重要,但同时也带来了前所未有的隐私挑战。先进的AI技术可以从理论上去标识化的医疗扫描中重新识别个人身份,例如从MRI数…

CentOS创建swap内存

服务器版本为CentOS7 一、检查现有 swap 空间 sudo swapon --show如果系统中没有 swap 空间或者现有的 swap 空间不足&#xff0c;可以继续后续步骤来创建 swap 空间。 二、创建 swap 文件&#xff08;推荐 2GB 作为示例&#xff09; sudo dd if/dev/zero of/swapfile bs1M …

在Android中如何使用Protobuf上传协议

在 Android 中使用 Protobuf&#xff08;Protocol Buffers&#xff09;主要分为以下几个步骤&#xff1a; ✅ 1. 添加 Protobuf 插件和依赖 在项目的 build.gradle&#xff08;Project 级&#xff09;文件中添加 Google 的 Maven 仓库&#xff08;通常默认已有&#xff09;&am…

Android学习总结之ANR问题

一、ANR 基础概念与核心原理&#xff08;必考题&#xff09; 1. 什么是 ANR&#xff1f;为什么会发生 ANR&#xff1f; 答案要点&#xff1a; 定义&#xff1a;ANR&#xff08;Application Not Responding&#xff09;即应用无响应&#xff0c;是 Android 系统检测到主线程&…