优先级反转是一个bug,表现为 高优先级的task被低优先级的task间接抢占。例如,低优先级的task占用着某个mutex,高优先级的task就必须等待 才能继续执行。
简单case:高优先级的task(Task H)会被阻塞,只要低优先级的task(Task L)拿着lock。这被称作“有界优先级反转”,因为优先级反转的时长 和低优先级task在临界区(hold the lock)的时长 相关。
上图可以看出,只要Task L 拿着lock,Task H 就会一直被阻塞 。tasks的优先级现在已经间接性的反转了,Task L在Task H前running。
无边界的优先级反转这种情况会出现:当一个中间优先级的task(Task M)在Task L拿着lock的时候打断Task L。这叫“无边界”,因为Task M现在可以随意阻塞Task H,因为Task M正在抢占Task L。
优先级反转在 1997 年差点终结了火星探路者任务。在部署火星车后,由于间歇性优先级倒置错误导致看门狗定时器触发完整的系统重启,着陆器每隔几天就会随机重置。 工程师最终发现了这个漏洞,并向着陆器发送了更新补丁。 您可以在此处阅读有关任务和错误的信息。
有两个常用的方法防止优先级反转,优先级天花板 和 优先级继承。
优先级天花板 是为每个资源或锁分配一个“优先级上限级别”。 每当任务使用特定资源或获取锁时,任务的优先级会自动提升到与锁或资源关联的优先级上限。 优先级上限由需要使用资源或锁的任何任务的最大优先级决定。
由于锁的优先级上限为 3,每当任务 L 获得锁时,它的优先级就会提升到 3,这样它就会以与任务 H 相同的优先级运行。这会阻止任务 M(优先级 2)一直运行到任务 L 和 H 完成了锁。
另一种称为“优先级继承”的方法 是将持有锁的任务的优先级提高到任何其他(更高优先级)尝试获取锁的任务的优先级。
task L 获取锁。 只有当task H 尝试获取锁时,task L 的优先级才会提升到tsk H 的优先级。 再一次,任务 M 不能再中断任务 L,直到两个任务都在临界区完成。
请注意,在优先级上限协议和优先级继承中,一旦任务 L 释放锁,它的优先级就会下降到原来的水平。 另请注意,这两个系统都只防止无限的优先级反转。 有界优先级反转仍然可能发生。
我们只能通过良好的编程实践来避免或减轻有界优先级反转。 一些可能的提示包括(根据您的项目需要进行选择):
保持临界区部分简短,以减少有限的优先级反转时间避免使用可能阻塞高优先级任务的临界区或锁定机制使用一项任务来控制共享资源,以避免需要创建锁来保护它
最后一点,可以用“service task”负责管理共享资源。例如,可以基于处理串行端口的task 使用 队列发送和接受messages
虽然实现另一个任务需要额外的开销,但我们可以使用这种方法有效地避免需要串行端口(或其他资源)的关键部分。
Recommended ReadingHow to use priority inheritance: https://www.embedded.com/how-to-use-priority-inheritance/
Priority inversion: https://barrgroup.com/embedded-systems/how-to/rtos-priority-inversion
What really happened on Mars rover Pathfinder: http://www.cs.cornell.edu/courses/cs614/1999sp/papers/pathfinder.html
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)