1 原子变量
- 定义gpioled设备结构体
- 初始化原子变量
- 使用原子变量
- 释放原子变量
2 自旋锁
- 原子操作只能对整形变量或者位进行保护,但是,在实际的使用环境中怎么可能只有整形变量或位这么简单的临界区。举个最简单的例子,设备结构体变量就不是整型变量,我们对于结构体中成员变量的操作也要保证原子性,在线程 A 对结构体变量使用期间,应该禁止其他的线程来访问此结构体变量,这些工作原子操作都不能胜任,需要、锁机制,在Linux内核中就是自旋锁。
- 定义gpioled设备结构体
- 初始化自选锁
- 打开设备
- 关闭/释放设备
3 信号量
- 相比于自旋锁,信号量可以使线程进入休眠状态,比如 A 与 B、C 合租了一套房子,这个房子只有一个厕所,一次只能一个人使用。某一天早上 A 去上厕所了,过了一会 B 也想用厕所,因为 A 在厕所里面,所以 B 只能等到 A 用来了才能进去。
B 要么就一直在厕所门口等着,等 A 出来,这个时候就相当于自旋锁。B 也可以告诉 A,让 A 出来以后通知他一下,然后 B 继续回房间睡觉,这个时候相当于信号量。可以看出,使用信号量会提高处理器的使用效率,毕竟不用一直傻乎乎的在那里“自旋”等待。但是,信号量的开销要比自旋锁大,因为信号量使线程进入休眠状态以后会切换线程,切换线程就会有开销。- ①、因为信号量可以使等待资源线程进入休眠状态,因此适用于那些占用资源比较久的场合。
- ②、因此信号量不能用于中断中,因为信号量会引起休眠,中断不能休眠。
- ③、如果共享资源的持有时间比较短,那就不适合使用信号量了,因为频繁的休眠、切换线程引起的开销要远大于信号量带来的那点优势
- down_interruptible和down的区别:
- down_interruptible 先去获取信号量(flag),如果信号量(flag)被占用,先把该进程加入到等待队列,然后查询当前进程是否有信号(软中断)要去处理,如果有的话会返回–EINTR退出,如果没有的话,当前进程进入可接受信号(软中断)唤醒的睡眠,如果睡眠期间有信号(软中断)打断同样会退出睡眠返回–EINTR,当然睡眠期间如果获取到信号量(flag)也会退出睡眠,即被 up操作 从等待队列上唤醒。
- Down操作,跟down_interruptible类似,先去获取信号量(flag),如果信号量(flag)被占用,先把该进程加入到等待队列,然后查询当前进程是否有信号(软中断)要去处理,如果有的话会返回–EINTR退出,如果没有的话,当前进程进入不可被信号(软中断)唤醒的睡眠,也就是睡眠过程中不响应信号(软中断),直到获取到信号量(flag)退出睡眠,即被 up操作 从等待队列上唤醒。
- 定义gpioled设备结构体
- 初始化信号量
- 打开设备
- 关闭/释放设备
- 实验现象
4 互斥体
- 在 FreeRTOS 和 UCOS 中也有互斥体,将信号量的值设置为 1 就可以使用信号量进行互斥访问了,虽然可以通过信号量实现互斥,但是 Linux 提供了一个比信号量更专业的机制来进行互斥,它就是互斥体—mutex。互斥访问表示一次只有一个线程可以访问共享资源,不能递归申请互斥体。在我们编写 Linux 驱动的时候遇到需要互斥访问的地方建议使用 mutex
- 定义gpioled设备结构体
- 打开设备
- 关闭/释放设备
- 初始化互斥体