在进行基于实时操作系统(RTOS)开发的项目期间,通常会遇到需要处理互斥情况的情况,比如:有几个任务需要同时使用一个UART串口来发送数据。
如果不采取互斥机制,当优先级较高的任务抢占串口并开始发送数据时,可能会导致发送的数据出现乱码的情况。
今天我想详细介绍一下在RTOS开发中经常遇到的一个问题,那就是互斥锁。
什么是互斥锁(Mutex)?
对于已经学习过RTOS的读者来说,互斥锁应该并不陌生。互斥锁是一种设计用来避免任务之间相互抢占某些资源的“锁”。
正如之前提到的例子,当两个任务同时竞争一个串口资源时,如果没有采用互斥锁的机制,就会导致两个任务交叉发送数据,从而导致数据出现乱码的情况。
但是,如果加了互斥锁,则会等待其他任务发送完成之后才继续发送,保证了数据的完整(而不是乱码);
Mutex互斥锁例子
这里以三个任务、两个互斥锁为例,代码如下:
void task1()
{
/*do something*/
OSMutex1_Pend(); //互斥锁1加锁
/*加锁处理事情*/
OSMutex1_Post(); //互斥锁1解锁
}
void task2()
{
/*do something*/
OSMutex1_Pend(); //互斥锁1加锁
OSMutex2_Pend(); //互斥锁2加锁
/*加锁处理事情*/
OSMutex2_Post(); //互斥锁2解锁
OSMutex1_Post(); //互斥锁1解锁
}
void task3()
{
/*do something*/
OSMutex2_Pend(); //互斥锁2加锁
/*加锁处理事情*/
OSMutex2_Post(); //互斥锁1解锁
}
这样设计,大家看出问题了吗?
老司机应该看出来了,新手可能摸不着头脑。
在任务2中,进行了2次加锁、解锁,而且“环环相扣”。
Mutex互斥锁问题
假如任务1、 任务2、 任务3优先级分别为:1、 2、 3。
优先级顺序就是:任务1 > 任务2 > 任务3(数字越小代表任务优先级越高)。
假设:任务1和任务2处于等待事件状态,也就是处于阻塞状态, task 3 处于运行状态。
当任务3在“加锁处理事情”的时候,任务2抢占了任务3(任务2挂起时间到了),此时任务3挂起,任务2处于运行状态;
如果任务2在“互斥锁1加锁”之后,任务1抢占了任务2,此时,任务1处于运行状态;
这个时候,你发现问题了没有?
任务1在执行“OSMutex1_Pend();”会等待“互斥锁1解锁”,如果其他方式没有对“互斥锁1解锁”,则会出现“死锁”的情况。
分享一张图片,你就会明白什么是死锁了:
解决办法
比如对任务2加锁方式进行改善:
void task2()
{
/*do something*/
OSMutex1_Pend(); //互斥锁1加锁
/*do something*/
OSMutex1_Post(); //互斥锁1解锁
OSMutex2_Pend(); //互斥锁2加锁
/*do something*/
OSMutex2_Post(); //互斥锁1解锁
}
或者对低优先级的任务3加锁方式进行改善:
void task3()
{
/*do something*/
OSMutex1_Pend(); //互斥锁1加锁
OSMutex2_Pend(); //互斥锁2加锁
/*加锁处理事情*/
OSMutex2_Post(); //互斥锁2解锁
OSMutex1_Post(); //互斥锁1解锁
}
出问题的原因, 当一个任务获得了临界区资源的锁,在没有释放这个锁的前提下又去获得另外一块临界区资源,这个时候就要引起足够的注意了,设计成败在于你是否彻底理解了之前的问题。
但是,归根到底这样的问题还是要求用户在设计阶段去避免,一个系统不可能是万能的,正确的设计才是最重要的。
以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !