什么是优先级反转?

Posted

技术标签:

【中文标题】什么是优先级反转?【英文标题】:What is priority inversion? 【发布时间】:2011-05-14 05:20:14 【问题描述】:

我听说过关于操作系统开发的“优先级反转”这个词。

究竟什么是优先级倒置?

它要解决的问题是什么,它是如何解决的?

【问题讨论】:

对于任何有兴趣的人drdobbs.com/jvm/what-is-priority-inversion-and-how-do-yo/… 视觉解释:cmdlinelinux.blogspot.com/2013/12/… 【参考方案1】:

想象三 (3) 个不同优先级的任务:tLow、tMed 和 tHigh。 tLow 和 tHigh 在不同时间访问同一个关键资源; tMed 做自己的事。

    tLow 正在运行,tMed 和 tHigh 目前被阻止(但不在临界区)。 tLow 出现并进入临界区。 tHigh 解除阻塞,因为它是系统中优先级最高的任务,所以它会运行。 tHigh 然后尝试进入关键资源,但由于 tLow 在其中而被阻止。 tMed 解除阻塞,因为它现在是系统中优先级最高的任务,所以它会运行。

在 tLow 放弃资源之前,tHigh 无法运行。 tLow 无法运行,直到 tMed 阻塞或结束。任务的优先级已倒置; tHigh 虽然具有最高优先级,但位于执行链的底部。

要“解决”优先级倒置,必须将 tLow 的优先级提高到至少与 tHigh 一样高。有些人可能会将其优先级提高到可能的最高优先级。与提高 tLow 的优先级一样重要的是在适当的时间降低 tLow 的优先级。不同的系统会采用不同的方法。

何时放弃 tLow 的优先级...

    tLow 拥有的任何资源上没有其他任务被阻止。这可能是由于超时或资源释放造成的。 没有其他有助于提高 tLow 优先级的任务在 tLow 拥有的资源上被阻止。这可能是由于超时或资源释放造成的。 当等待资源的任务发生变化时,降低 tLow 的优先级以匹配在其资源上阻塞的最高优先级任务的优先级。

方法 #2 是对方法 #1 的改进,因为它缩短了 tLow 的优先级提升的时间长度。请注意,在此期间其优先级保持在 tHigh 的优先级。

方法 #3 允许 tLow 的优先级在必要时逐步降低,而不是在一个全有或全无的步骤中。

不同的系统会根据他们认为重要的因素实施不同的方法。

内存占用 复杂性 实时响应 开发者知识

希望这会有所帮助。

【讨论】:

谢谢。我曾经负责为一个商业 RTOS 实现一个优先级继承算法——fun times。 :) @Sparky 那么在第 4 步中 tLow 将被赋予 tHigh 的优先级是否正确,直到 tLow 解除对临界区的阻塞? @Ian - 当有优先级反转保护时,您可以期望 tLow 将被赋予至少与 tHigh 一样高的优先级。它将保持该优先级,直到 tHigh 不再被该资源阻塞(可能更长时间)。 很好的解释,但我会明确地将调度程序带到图片中,因为它使完整的问题成为可能。【参考方案2】:

优先级倒置是一个问题,而不是解决方案。典型的例子是低优先级进程获取高优先级进程需要的资源,然后被中优先级进程抢占,所以高优先级进程在资源上阻塞,而中优先级进程完成(实际上是用较低的优先级)。

一个相当著名的例子是火星探路者火星车遇到的问题:http://www.cs.duke.edu/~carla/mars.html,读起来很有趣。

【讨论】:

我很困惑!为什么高优先级进程不能从一开始就抢占低优先级进程?中优先级的进程可以做到这一点,高优先级的进程肯定也可以做到吗?我现在已经阅读了很多关于这个主题的解释,但我觉得缺少一些东西。 假设 HP 进程定期产生,因此其他进程确实运行。只有当它试图获取 LP 已经拥有的资源时,才会出现问题。 @Viktor 高优先级任务不会 100% 运行。当它不运行时,一个低优先级的任务可能会出现并获取一个互斥锁。在工作的中间,一个中等进程出现并抢占了低运行任务。然后高优先级任务唤醒并想要获取低优先级任务现在拥有的互斥锁。但是高优先级任务现在无法获取互斥锁 - 它由低优先级进程拥有 - 所以现在有一个问题,高优先级任务无法继续前进。 @Viktor 我也很困惑,但关键信息是高优先级线程和低优先级线程有一个共同的互斥锁。高优先级线程不能抢占低优先级,因为它们试图使用相同的资源,它必须等待低优先级完成。另一方面,中等优先级线程可以控制,因为它不依赖于相同的共享资源。所以中优先级线程让低优先级线程休眠并接管。 nos + Nattrass 的答案是完美的!【参考方案3】:

假设一个应用程序有三个线程:

Thread 1 has high priority.
Thread 2 has medium priority.
Thread 3 has low priority.

假设线程 1 和线程 3 共享相同的临界区代码

线程 1 和线程 2 在示例开始时处于休眠或阻塞状态。线程 3 运行并进入临界区。

此时,线程 2 开始运行,抢占线程 3,因为线程 2 具有更高的优先级。因此,线程 3 继续拥有一个临界区。

稍后,线程 1 开始运行,抢占线程 2。线程 1 尝试进入线程 3 拥有的临界区,但由于它被另一个线程拥有,线程 1 阻塞,等待临界区。

此时,线程 2 开始运行,因为它的优先级高于线程 3,而线程 1 没有运行。线程 3 永远不会释放线程 1 正在等待的临界区,因为线程 2 会继续运行。

因此,系统中最高优先级的线程,线程 1,被阻塞,等待低优先级的线程运行。

【讨论】:

比上面所有例子都更好的解释 这个问题究竟是如何解决的。我猜在线程 1 想要进入临界区的那一刻,线程 3 将被赋予线程 1 的优先级。因为那时不会安排线程 2,而是安排线程 3,对吗? 值得注意的是,线程 2 不必等待,因为它有自己的代码块来执行,并且没有与线程 1 和 3 相同的临界区代码来执行。跨度> 【参考方案4】:

是the problem,而不是解决方案。

它描述了当低优先级线程在工作期间获得锁时,高优先级线程将不得不等待它们完成(由于它们是低优先级,这可能需要特别长时间)。这里的反转是高优先级线程不能继续,直到低优先级线程执行,所以实际上它现在也具有低优先级。

一种常见的解决方案是让低优先级的线程暂时继承等待他们持有的锁的每个人的高优先级。

【讨论】:

【参考方案5】:

[假设,低进程 = LP,中进程 = MP,高进程 = HP]

LP 正在执行一个临界区。在进入临界区时,LP 必须获得某个对象的锁定,例如 OBJ。 LP 现在位于临界区内。

同时,HP 被创建。由于优先级较高,CPU 会进行上下文切换,HP 现在正在执行(不是同一个临界区,而是一些其他代码)。在 HP 执行期间的某个时间点,它需要对同一个 OBJ 的锁(可能在同一个临界区,也可能不在同一个临界区),但 OBJ 上的锁定仍然由 LP 持有,因为它在执行临界区时被抢占. LP 现在不能放弃,因为进程处于 READY 状态,而不是 RUNNING。现在 HP 进入 BLOCKED / WAITING 状态。

现在,MP 进来并执行它自己的代码。 MP 不需要锁定 OBJ,因此它会继续正常执行。 HP 等待 LP 释放锁定,LP 等待 MP 完成执行,以便 LP 可以回到 RUNNING 状态(..并执行并释放锁定)。只有在 LP 释放锁之后,HP 才能回到 READY(然后通过抢占低优先级任务进入 RUNNING。)

因此,实际上这意味着在 MP 完成之前,LP 无法执行,因此 HP 无法执行。因此,看起来 HP 正在等待 MP,即使它们没有通过任何 OBJ 锁直接相关。 -> 优先级反转.

优先级反转的解决方案是Priority Inheritance -

将进程 (A) 的优先级提高到任何进程的最大优先级 其他进程正在等待 A 拥有资源锁的任何资源。

【讨论】:

【参考方案6】:

让我说得非常简单明了。 (此答案基于上述答案,但以简洁的方式呈现)。

假设有一个资源 R 和 3 个进程。 LMH。其中p(L) < p(M) < p(H)(其中p(X)X 的优先级)。

L 首先开始执行并在 R 上捕获保持。 (R 的独家访问权限) H 来晚了,也想独占访问R,由于L 持有它,H 必须等待。 M 位于 H 之后,它不需要 R。由于M 已经得到了它想要执行的所有内容,它迫使L 离开,因为它与L 相比具有更高的优先级。但是H 不能这样做,因为它有一个被L 锁定的资源,它需要执行。

现在让问题更清楚了,实际上M 应该等待H 完成,因为p(H) > p(M) 没有发生,这本身就是问题所在。如果出现许多进程,例如M,并且不允许L 执行并释放锁定H,则将永远不会执行。这在时间紧迫的应用程序中可能是危险的

对于解决方案,请参阅上述答案:)

【讨论】:

【参考方案7】:

优先级反转是指较低优先级进程获取较高优先级进程所需的资源,从而阻止较高优先级进程继续进行,直到资源被释放。

例如: FileA 需要被 Proc1 和 Proc2 访问。 Proc 1 的优先级高于 Proc2,但 Proc2 设法先打开 FileA。

通常,Proc1 的运行频率可能是 Proc2 的 10 倍,但由于 Proc2 正在保存文件,因此无法执行任何操作。

所以最终发生的事情是 Proc1 阻塞,直到 Proc2 完成 FileA,本质上它们的优先级是“反转”的,而 Proc2 持有 FileA 的句柄。

就“解决问题”而言,如果不断发生优先级倒置本身就是一个问题。 最坏的情况(尽管大多数操作系统不会让这种情况发生)是如果 Proc2 在 Proc1 之前不允许运行。这将导致系统锁定,因为 Proc1 将继续获得分配的 CPU 时间,而 Proc2 将永远不会获得 CPU 时间,因此永远不会释放文件。

【讨论】:

我认为您是在解释阻塞而不是优先级倒置。优先级反转发生在中等优先级进程运行在较高优先级进程之前,因为较低优先级进程占用了较高优先级进程所需的资源。此外,您得出结论“文件将永远不会被释放”。您的示例只有 2 个进程。如果 Proc1 使用 FileA 完成,它将释放文件。如果它忘记这样做,那是一个糟糕的编程问题,而不是优先级倒置的问题。【参考方案8】:

优先级反转如下: 给定进程 H、M 和 L,其中名称代表高、中和低优先级, 只有 H 和 L 共享一个公共资源。

说,L首先获取资源并开始运行。由于 H 也需要该资源,因此它进入等待队列。 M 不共享资源并且可以开始运行,因此它确实如此。当 L 被任何方式中断时,M 进入运行状态,因为它具有更高的优先级,并且在中断发生的瞬间运行。 虽然 H 的优先级比 M 高,但由于它在等待队列中,所以它无法获取资源,这意味着比 M 还要低的优先级。 在 M 完成后,L 将再次接管 CPU,导致 H 一直等待。

【讨论】:

【参考方案9】:

如果被阻塞的高优先级线程将其高优先级转移到占用资源的低优先级线程,则可以避免优先级反转。

【讨论】:

【参考方案10】:

当较高优先级的进程需要读取或修改当前正在由较低优先级进程(或一系列较低优先级进程)访问的内核数据时,就会出现调度挑战。由于内核数据通常被锁保护,高优先级的进程将不得不等待低优先级的进程完成资源。如果优先级较低的进程被优先级较高的另一个进程抢占,情况会变得更加复杂。例如,假设我们有三个进程——L、M 和 H——它们的优先级遵循 L

【讨论】:

照原样复制【参考方案11】:

考虑一个具有两个进程的系统,H 具有高优先级,L 具有低优先级。调度规则是这样的:H 因为它的高优先级而在它处于就绪状态时运行。在某个时刻,L 在其临界区,H 准备好运行(例如,I/O 操作完成)。 H 现在开始忙于等待,但由于 L 从未在 H 运行时被安排,L 永远没有机会离开临界区。所以H 永远循环。

这种情况称为Priority Inversion。因为高优先级的进程正在等待低优先级的进程。

【讨论】:

以上是关于什么是优先级反转?的主要内容,如果未能解决你的问题,请参考以下文章

信号量优先级反转(翻转)与优先级继承

在优先级反转问题上,我们应该更改互斥锁或线程的属性吗?

优先级调度优先级反转优先级继承优先级天花板

表达式中移位和按位补码的反转优先级

不能在 C++ 中引发优先级反转

优先级反转和解决方法