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

8.1linux竞争与并发知识讲解(尽可能详细)_csdn

Linux是一个多任务操作系统,肯定会存在多个任务共同操作同一段内存或者设备的情况,多个任务甚至中断都能访问的资源叫做共享资源,就和共享单车一样。在驱动开发中要注意对共享资源的保护,也就是要处理对共享资源的并发访问。比如共享单车,大家按照谁扫谁骑走的原则来共用这个单车,如果没有这个并发访问共享单车的原则存在,只怕到时候为了一辆单车要打起来了。

1、并发与竞争简介

Pasted image 20250306135841.png
打印机必须保证一次只能打印一份文档,只有打印完成以后才能打印其他的文档。
Pasted image 20250306140238.png
临界区就是共享数据段,对于临界区必须保证一次只有一个线程访问。
也就是要保证临界区是原子访问的,注意这里的==“原子==”不是正点原子的“原子”。
我们都知道,原子是化学反应不可再分的基本微粒,这里的原子访问就表示这一个访问是一个步骤不能再进行拆分。如果多个线程同时操作临界区就表示存在竞争,我们在编写驱动的时候一定要注意避免并发和防止竞争访问
重点:我们一般在编写驱动的时候就要考虑到并发与竞争,而不是驱动都编写完了然后再处理并发与竞争。
Pasted image 20250306141039.png

2、原子操作

2.1、原子整形操作 API 函数

一次只允许一个应用程序。
Pasted image 20250306142058.png
内核里面的东西已经做好!
Pasted image 20250306142149.png
Pasted image 20250306142440.png
用的STM32MP157是32位的架构。
Pasted image 20250306142640.png

2.2、原子位操作 API 函数

位操作也是很常用的操作, Linux 内核也提供了一系列的原子位操作 API 函数,只不过原子位操作不像原子整形变量那样有个 atomic_t 的数据结构,原子位操作是直接对内存进行操作
Pasted image 20250306143106.png
Pasted image 20250306143119.png

3、自旋锁

Pasted image 20250306143757.png
Linux 内核使用结构体 spinlock_t 表示自旋锁,结构体定义如下所示:
Pasted image 20250306143845.png
Pasted image 20250306143903.png
Pasted image 20250306143919.png

3.1、自旋锁API函数

Pasted image 20250306144347.png
Pasted image 20250306144837.png
Pasted image 20250306145328.png
Pasted image 20250306145356.png
这个意思就是:假如没有开启禁止本地中断,在线程A在获取锁后,中断开始想获取这个锁,但是因为线程A占了这个锁,所以中断没法执行,但是中断调用函数优先权比线程A高,线程A不可能执行,所以僵持下去了!
假如没有这个锁,线程A一旦被中断事件中断,就必须让出cpu使用。先中断后线程A。
最好的解决方法就是获取锁之前关闭本地中断。
上面有API函数进行处理!
Pasted image 20250306151442.png
当线程开始时,禁止本地中断,获取自旋锁;当中断开始时,激活本地中断,释放自旋锁。
一般在线程中使用 spin_lock_irqsave/ spin_unlock_irqrestore,在中断中使用spin_lock/spin_unlock
例如:
Pasted image 20250306151636.png
Pasted image 20250306152358.png

3.2、其他类型的锁

3.2.1、读写自旋锁

Pasted image 20250306152930.png
这个意思是:只能一个线程进行写锁操作,支持多个线程进行读锁操作。修改数据只可以一个线程进行,读取数据可以多个线程同时进行。
Pasted image 20250306153112.png
读写锁操作 API 函数分为两部分,一个是给读使用的,一个是给写使用的。
Pasted image 20250306153151.png
Pasted image 20250306153832.png

3.2.2、顺序锁

顺序锁在读写锁的基础上衍生而来的,使用读写锁的时候读操作和写操作不能同时进行。使用顺序锁的话可以允许在写的时候进行读操作,也就是实现同时读写,但是不允许同时进行并发的写操作

虽然顺序锁的读和写操作可以同时进行,但是如果在读的过程中发生了写操作最好重新进行读取,保证数据完整性。
顺序锁保护的资源不能是指针,因为如果在写操作的时候可能会导致指针无效,而这个时候恰巧有读操作访问指针的话就可能导致意外发生,比如读取野指针导致系统崩溃
Linux 内核使用 seqlock_t 结构体表示顺序锁。
Pasted image 20250306154743.png
关于顺序锁的 API 函数如表:
Pasted image 20250306154813.png

3.3、顺序锁自旋锁使用注意事项

Pasted image 20250306154936.png

4、信号量

Pasted image 20250306155911.png
Pasted image 20250306160217.png
Pasted image 20250306161509.png
Pasted image 20250306161528.png

4.1信号量 API 函数

Pasted image 20250306170956.png
Pasted image 20250306171007.png
Pasted image 20250306171029.png

5、互斥体

将信号量的值设置为 1 就可以使用信号量进行互斥访问了。
虽然可以通过信号量实现互斥,但是 Linux 提供了一个比信号量更专业的机制来进行互斥,它就是互斥体—mutex。
互斥访问表示一次只有一个线程可以访问共享资源,不能递归申请互斥体。
在我们编写 Linux 驱动的时候遇到需要互斥访问的地方建议使用 mutex
使用 mutex 结构体表示互斥体,定义如下:
Pasted image 20250306171330.png

5.1、互斥体 API 函数

Pasted image 20250306171433.png
互斥体的使用:
Pasted image 20250306171459.png
关于 Linux 中的并发和竞争就讲解到这里, Linux 内核还有很多其他的处理并发和竞争的机制,本章我们主要讲解了常用的原子操作、自旋锁、信号量和互斥体。以后我们在编写 Linux驱动的时候就会频繁的使用到这几种机制。


http://www.kler.cn/a/579555.html

相关文章:

  • Virtual Sparse Convolution for Multimodal 3D Object Detection 论文阅读
  • Redis 缓存穿透、击穿、雪崩的 出现场景 与 解决方案
  • 数据库基础以及基本建库建表的简单操作
  • Linux下安装elasticsearch(Elasticsearch 7.17.23)
  • 基于Python的电商销售数据分析与可视化系统实
  • 开发环境搭建-06.后端环境搭建-前后端联调-Nginx反向代理和负载均衡概念
  • 升级到Android Studio 2024.2.2 版本遇到的坑
  • Linux安装升级docker
  • Mybatis操作数据库----小白基础入门
  • 【开源免费】基于SpringBoot+Vue.JS青年公寓服务平台(JAVA毕业设计)
  • [项目]基于FreeRTOS的STM32四轴飞行器: 五.Motor驱动
  • 关于Springboot 应配置外移和Maven个性化打包一些做法
  • 使用 QML 和 QtSql 实现 SQLite 数据库操作
  • NebulaGraph学习笔记-SessionPool之getSession
  • 【数据结构与算法】Java描述:第二节:LinkedList 链表
  • 【YOLOv12改进trick】三重注意力TripletAttention引入YOLOv12中,实现遮挡目标检测涨点,含创新点Python代码,方便发论文
  • OSPF报文分析
  • MySQL环境搭建和基本操作
  • 【大模型】WPS 接入 DeepSeek-R1详解,打造全能AI办公助手
  • vivado 充分利用 IP 核