基于RTOS开发项目时,我们通常会遇到互斥的情况,比如几个任务不得不使用一个UART串口发送数据。
如果不加互斥锁,优先级高的任务会抢占串口发送数据,所以可能会出现“乱码”的数据传输。
今天,我将谈谈RTOS开发中常见的互斥问题。
互斥是什么?
研究过RTOS的读者应该对互斥体很熟悉,互斥体是一种“锁”,旨在防止任务互相抢占一些资源。
如上所述,一个串口被两个任务占用。如果不锁,两个任务会交叉发送数据,即“乱码”;
但如果添加了互斥锁,会等待其他任务发送后再继续发送,保证数据的完整性(不乱码);
嵌入列
2
互斥体互斥体示例
这里,以三个任务和两个互斥体为例。代码如下:
void task 1(){OS mutex 1 _ Pend();//mutex 1 locksosmutex 1 _ Post();//互斥1解锁} void task 2(){OS mutex 1 _ pend();//互斥1锁定osmutex 2 _ Pend();//互斥2锁osmute x2 _ Post();//互斥2解锁osmutex 1 _ Post();//互斥1解锁} void task 3(){osmute x2 _ pend();//互斥2锁osmute x2 _ Post();//互斥1已解锁}
你看出这个设计的问题了吗?
老司机应该看到了,新手可能会疑惑。
在任务2中,锁定和解锁进行了两次,而且是“互锁”的。
互斥问题
假设任务1、任务2、任务3的优先级分别为1、2、 3。
优先级顺序为:任务1、任务2、任务3(数字越小,任务优先级越高)。
假设:任务1和任务2在等待一个事件,也就是被阻塞了,任务3在运行。
当任务3“被锁定处理事情”时,任务2抢占任务3(该任务2暂停了),此时任务3暂停,任务2处于运行状态;
如果任务2在互斥锁1之后被锁定,那么任务1会抢占任务2。此时,任务1正在运行。
这个时候,你发现问题了吗?
任务1正在执行"osmutex 1 _ Pend();"会等待“互斥1解锁”,如果互斥1没有通过其他方式解锁,就会出现“死锁”。
分享一张图你就明白什么是死锁了:
解决办法
例如,改进任务2的锁定模式:
void task 2(){OS mutex 1 _ Pend();//互斥1锁osmutex 1 _ Post();//互斥1解锁osmute x2 _ Pend();//互斥2锁osmute x2 _ Post();//互斥1已解锁}
或者改进低优先级任务3的锁定模式:
void task 3(){OS mutex 1 _ Pend();//互斥1锁定osmutex 2 _ Pend();//互斥2锁osmute x2 _ Post();//互斥2解锁osmutex 1 _ Post();//互斥1已解锁}
问题的原因是,当一个任务获得了临界区资源的锁,又在没有释放锁的情况下获得了另一个临界区资源,这个时候就会引起足够的重视。设计的成败取决于你是否透彻理解了前面的问题。但归根结底,这样的问题还是需要用户在设计阶段避免。一个系统不可能是万能的,正确的设计最重要。
审计彭静