linux线程用信号量还是互斥体,Linux 并发与竞争详解

目录

一、并发与竞争简介

二、原子操作

三、自旋锁

四、信号量

五、互斥体

一、并发与竞争简介

多个任务、中断都能访问的资源叫共享资源,在驱动开发中注意对共享资源的保护,防止共享资源的并发访问造成混乱。

1、什么是并发?

【答】:并发就是多个 “用户” 同时访问同一个共享资源,并发访问带来的问题就是竞争。

2、什么是竞争?

【答】:Linux 是多任务操作系统,肯定存在多个任务共同操作同一段内存或设备,这些任务可能会相互覆盖这段内存中的数据,造成内存数据混乱。

3、造成 Linux 系统并发产生的原因?

(1)多任务(线程)并发访问

(2)抢占式并发访问

(3)中断程序并发访问

(4)SMP(多核)核间并发访问

4、保护的内容是什么?

【答】:某个线程局部变量不需要保护,要保护的是多个线程都会访问的共享数据。如:全局变量,设备结构体成员。

二、原子操作

对于共享数据进行原子操作(不可分割的操作),一般原子操作用于变量或者位操作。

对于基本的赋值操作,如:a = 3,ARM 架构不支持直接对寄存器进行读写操作,它在 ARM 中执行的步骤:

ldr r0, =0X30000000 // 变量 a 地址

ldr r1, = 3 // 要写入的值

str r1, [r0] // 将 3 写入到 a 变量中

即 C 语言中的变量赋值语句,在汇编中转化成三行汇编指令,就有可能出现并发竞争问题,我们要保证三行汇编指令作为一个整体运行,Linux 内核提供了两组原子操作 API 函数,一组对整形变量进行操作,一组对位进行操作。

1、原子整形操作 API 函数

Linux 内核定义了叫做 atomic_t 的结构体来完成整形数据的原子操作,在使用中用原子变量来代替整形变量。

(1)使用原子操作 API 函数,首先要先定义一个 atomic_t 的变量,如:atomic_t a,即原子变量。

(2)调用 Linux 内核提供的大量原子操作 API 函数对原子变量进行操作。

2、原子位操作 API 函数

原子位操作不像原子整形变量那样有个 atomic_t 的数据结构,原子位操作是直接对内存进行操作。

注意:原子操作是用于变量,不一定非要是全局变量,也可以是结构体中的整形变量,它一般用于整形变量(int)和位操作,因为 Linux 内核提供了原子整形操作 API 函数和位操作 API 函数。

三、自旋锁

原子操作只能对整形变量或者位进行保护,使用自旋锁保护结构体变量,适用于短时期轻量级加锁,长时间就用信号量。

1、为什么称为 “自旋锁”?

(1)自旋:如果自旋锁正在被线程 A 持有,线程 B 想要获取自旋锁,那么线程 B 就会一直在原地等待,即等待自旋锁的线程会一直处于自旋状态,这样会浪费处理器时间,降低系统性能。

(2)锁:当一个线程要访问某个共享资源的时候首先要先加锁, 锁只能被一个线程持有,只要此线程不释放持有的锁,那么其他的线程就不能获取此锁。

2、自旋锁 API 函数

Linux 内核使用结构体 spinlock_t 表示自旋锁,使用用自旋锁之前,首先要定义一个自旋锁变量,如:spinlock_t a。

3、自旋锁使用注意事项

(1)等待自旋锁时处于 “自旋” 状态,因此锁的持有时间不能太长,一定要短,否则的话会降低系统性能。

(2)被自旋锁保护的临界区一定不能调用任何能够引起睡眠和阻塞的 API 函数,否则可能会导致死锁现象的发生。

(3)中断获取自旋锁时,在线程 A 获取锁之前一定要先禁止本地中断,等待线程 A 执行完后释放锁,中断才能获取锁。

f68a34e59d4f338f9b64603d08da826a.png

四、信号量

信号量可以使线程进入休眠状态,会切换线程,信号量的开销要比自旋锁大,适用于占用资源比较久的场合。

1、信号量类型

ac617d77cd03e2e3fe544a36fb120ed3.png

2、信号量 API 函数

Linux 内核使用 semaphore 结构体表示信号量,使用信号量之前,首先要定义信号量变量,如:struct semaphore a。

3、信号量使用注意事项

(1)信号量不能用于中断中,因为信号量会引起休眠,中断不能休眠。

(2)如果共享资源的持有时间较短,不适合使用信号量,因为频繁的休眠、切换线程造成很大开销。

五、互斥体

信号量值 = 1 可以实现互斥访问,Linux 比信号量更专业的机制来进行互斥,即互斥体 mutex。使用过程中有其它线程想要获取该资源的锁,那么它就会被阻塞陷入睡眠状态,直到该资源被解锁才会被唤醒。

1、互斥体 API 函数

Linux 内核使用 mutex 结构体表示互斥体,使用互斥体之前,首先要定义互斥体变量,如:struct mutex a。

2、互斥体使用注意事项

(1)mutex 可以导致休眠,因此不能在中断中使用 mutex,中断中只能使用自旋锁。

(2)和二值信号量一样, mutex 保护的临界区可以调用引起阻塞的 API 函数,阻塞函数进入休眠状态,直到资源解锁被唤醒。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值