7.互斥锁¶

7.2. 互斥锁的优先级继承机制¶

在 LiteOS中为了降低优先级翻转产生的危害使用了优先级继承算法,优先级继承算法是指:暂时提高占有某种临界资源的低优先级任务的优先级,

使之与在所有等待该资源的任务中,优先级最高的任务优先级相等,而当这个低优先级任务执行完毕释放该资源时,优先级恢复初始设定值(此处

可以看作是低优先级任务继承了高优先级任务的优先级)。因此,继承优先级的任务避免了系统资源被任何中间优先级的任务抢占。

互斥锁与二值信号量最大的区别是:互斥锁具有优先级继承机制,而信号量没有。也就是说,某个临界资源受到一个互斥锁保护。任务访问该资源

时需要获得互斥锁,如果这个资源正在被一个低优先级任务使用,那么此时的互斥锁是闭锁状态,其他任务不能获得该互斥锁,如果此时一个高优

先级任务想要访问该资源,那么高优先级任务会因为获取不到互斥锁而进入阻塞态,系统会将当前持有该互斥锁任务的优先级临时提升到与高优先

级任务相同,这就是优先级继承机制,它确保高优先级任务进入阻塞状态的时间尽可能短,以及将已经出现的“优先级翻转”危害降低到最小。

任务的优先级在任务创建的时候就已经指定,高优先级的任务可以打断低优先级的任务,抢占CPU的使用权。但是在很多场合中,某些资源只有一

个,当低优先级任务正在占用该资源的时候,互斥锁处于闭锁状态,即便是高优先级任务也只能等待低优先级任务释放互斥锁,然后高优先级任务

才能获得互斥锁去访问该资源。高优先级任务无法运行而低优先级任务可以运行的现象称为“优先级翻转”。

为什么说优先级翻转在操作系统中是危害很大?因为在一开始设计系统的时候,就已经指定任务的优先级了,越重要的任务优先级越高。但是发生

优先级翻转,会导致系统的高优先级任务阻塞时间过长,得不到有效的处理,有可能对整个系统产生严重的危害,同时也违法了操作系统可抢占调度的原则。

举个例子,当前系统中存在三个任务,分别为H任务(High)、M任务(Middle)、L任务(Low),三个任务的优先级顺序为H任务>M任务>L任务。

正常运行的时候H任务可以打断M任务与L任务,M任务可以打断L任务。假设系统中存在一个临界资源,此时该资源被L任务正在使用中,某一时刻,

H任务需要使用该资源,但此时L任务还未释放资源,H任务则因为获取不到该资源使用权而进入阻塞态,L任务继续使用该资源,此时已经出现了

“优先级翻转”现象,高优先级任务在等待低优先级的任务执行,如果在L任务执行的时候刚好M任务被唤醒了,由于M任务优先级比L任务优先级高,

那么会打断L任务,抢占L任务的CPU使用权,直到M任务执行完,再把CPU使用权归还给L任务,L任务继续执行,等到执行完毕之后释放该资源,

此时H任务才能从阻塞态解除,使用该资源。这个过程,本来是最高优先级的H任务,等待了更低优先级的L任务与M任务,其阻塞的时间是M任务运

行时间+L任务运行时间,假如系统中有多个如M任务这样的中间优先级任务抢占最低优先级任务CPU使用权,那么系统最高优先级的任务将持续阻

塞,这是绝对不允许出现的。因此在没有优先级继承的情况下,保护临界资源将有可能产生优先级翻转,其危害极大,优先级翻转过程示意图如

图 优先级翻转示意图 所示。

优先级翻转示意图 (1):L任务正在使用某临界资源, H任务被唤醒,执行H任务。但L任务并未执行完毕,此时临界资源还未释放。

优先级翻转示意图 (2):这个时刻H任务也要对该临界资源进行访问,但 L任务还未释放资源,由于保护机制,H任务进入阻塞态,L任务得以继续运行,此时已经发生了优先级翻转现象。

优先级翻转示意图 (3):某个时刻M任务被唤醒,由于M任务的优先级高于L任务, M任务抢占了CPU的使用权,M任务开始运行,此时L任务尚未执行完,临界资源还未被释放。

优先级翻转示意图 (4):M任务运行结束,归还CPU使用权,L任务继续运行。

优先级翻转示意图 (5):L任务运行结束,释放临界资源,H任务得以对资源进行访问,H任务开始运行。

如果H任务的等待时间过长,对整个系统来说可能是致命的,所以尽可能降低高优先级任务的等待时间以此降低优先级翻转的危害,

而互斥锁就是用于临界资源的保护,并且其特有的优先级继承机制可以降低优先级翻转的产生的危害。

假如系统使用互斥锁保护临界资源,那么就具有优先级继承特性,任务需要在获取互斥锁后才能访问临界资源。在H任务获取互斥锁时,

由于获取不到互斥锁进入阻塞态,那么系统就会把当前正在使用资源的L任务的优先级临时提升到与H任务优先级相同,当M任务被唤醒时,

因为它的优先级比H任务低,所以无法打断L任务,因为此时L任务的优先级被临时提升到H,所以当L任务使用完该资源候释放互斥锁,

H任务将获得互斥锁而恢复运行。因此H任务的阻塞时间仅仅是L任务的执行时间,此时的优先级的危害降到了最低,这就是优先级继承

的优势,其示意图如图 优先级继承示意图 所示。

优先级继承示意图 (1): L任务正在使用某临界资源, H任务被唤醒,执行H任务。但L任务尚未运行完毕,此时互斥锁还未释放。

优先级继承示意图 (2):某一时刻H任务也要获取互斥锁访问该资源,由于互斥锁对临界资源的保护机制,H任务无法获得互斥锁而进入阻

塞态。此时发生优先级继承,系统将L任务的优先级暂时提升到与H任务优先级相同,L任务继续执行。

优先级继承示意图 (3):在某一时刻M任务被唤醒,由于此时M任务的优先级暂时低于L任务,所以M任务仅在就绪态,而无法获得CPU使用权。

优先级继承示意图 (4):L任务运行完毕释放互斥锁,H任务获得互斥锁后恢复运行,此时L任务的优先级会恢复初始指定的优先级。

优先级继承示意图 (5):当H任务运行完毕,M任务得到CPU使用权,开始执行。

优先级继承示意图 (6):系统正常运行,按照初始指定的优先级运行。

使用互斥锁的时候一定需要注意以下几点。

在获得互斥锁后,请尽快释放互斥锁。

在任务持有互斥锁的这段时间,不得更改任务的优先级。

LiteOS的优先级继承机制不能解决优先级翻转,只能将这种情况的影响降低到最小,硬实时系统在一开始设计时就要避免优先级翻转发生。

互斥锁不能在中断服务函数中使用。