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

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驱动的时候就会频繁的使用到这几种机制。

相关文章:

  • pta L1-003 个位数统计
  • LeetCode 738. 单调递增的数字 java题解
  • 2.装饰器模式
  • 计算机安全 第四节:访问控制(上)
  • Qt常用控件之分组框QGroupBox
  • Express Router 全面教程与最佳实践
  • k8s下部署ansible进行node-export二安装
  • 使用PHP实现异步编程:挑战与解决方案
  • 【数据结构】一文解析跳表
  • 【leetcode100】组合总和
  • 大规模分布式训练技术
  • LINUX SERVER在那種情況下需要做Raid
  • RabbitMQ应用问题大全(精心整理版)
  • 【MATLAB例程】二维环境定位,GDOP和CRLB的计算
  • JVM面试题
  • 【Agent的革命之路——LangGraph】如何使用config
  • Eclipse Kura:开源的物联网网关框架
  • Python入门———条件、循环
  • 认识Event Loop【1】
  • HCIP复习拓扑练习
  • 北京北站/seo 优化教程
  • 昆钢建设集团网站/成都seo培训
  • 做网站的技术要求/网站seo优化步骤
  • 家政服家政服务网站模板/南昌seo排名
  • 嘉兴网站建设推广/如何提升百度关键词排名
  • 硬件开发学什么专业/站长之家seo综合