オペレーティングシステムの開発に関して「優先順位の逆転」というフレーズを聞いたことがあります。
優先順位の逆転とは正確には何ですか?
解決しようとしている問題とは何ですか?
優先順位の逆転は問題であり、解決策ではありません。典型的な例は、低優先度プロセスが高優先度プロセスが必要とするリソースを取得し、中優先度プロセスによってプリエンプトされるため、中優先度プロセスが終了する間、高優先度プロセスはリソース上でブロックされます(実質的により低い優先度)。
かなり有名な例は、Mars Pathfinderローバーが経験した問題でした: http://www.cs.duke.edu/~carla/mars.html 、それはかなり興味深い読み物です。
優先度の異なる3つのタスク、tLow、tMed、およびtHighを想像してください。 tLowとtHighは、異なる時間に同じ重要なリソースにアクセスします。 tMedは独自の処理を行います。
tHighは、tLowがリソースを放棄するまで実行できません。 tLowは、tMedがブロックまたは終了するまで実行できません。タスクの優先順位が逆になりました。最も高い優先度を持っているけれども、tHighは実行チェーンの下部にあります。
優先順位の逆転を「解決」するには、tLowの優先順位を少なくともtHighと同じ高さに上げる必要があります。優先度を可能な限り最高の優先レベルに引き上げることもできます。 tLowの優先度を上げるのと同じくらい重要なのは、適切な時間にtLowの優先度を落とすことです。システムが異なれば、アプローチも異なります。
TLowの優先順位をいつ削除するか...
方法#2は、方法#1よりも改善されており、tLowの優先度レベルが上げられている時間を短縮します。この期間中、その優先レベルはtHighの優先レベルでバンプされたままであることに注意してください。
方法#3では、必要に応じて、1つの全か無かのステップではなく、tLowの優先度レベルを段階的に下げることができます。
システムが異なれば、重要だと考える要因に応じて異なる方法が実装されます。
お役に立てれば。
解決策ではなく 問題 です。
優先度の低いスレッドが作業中にロックを取得する場合、優先度の高いスレッドが終了するのを待たなければならない状況について説明します(優先度が低いため特に時間がかかる場合があります)。ここでの反転は、高優先度のスレッドは低優先度のスレッドが継続するまで継続できないため、事実上、現在は低優先度のスレッドでもあります。
一般的な解決策は、優先度の低いスレッドが、保持しているロックを待機している全員の優先度を一時的に継承することです。
アプリケーションに3つのスレッドがあるとします。
Thread 1 has high priority.
Thread 2 has medium priority.
Thread 3 has low priority.
スレッド1とスレッド3が同じクリティカルセクションコードを共有すると仮定しましょう
スレッド1とスレッド2は、例の最初にスリープまたはブロックされています。スレッド3が実行され、クリティカルセクションに入ります。
その時点で、スレッド2の実行が開始され、スレッド2の優先順位が高いため、スレッド3が横取りされます。そのため、スレッド3は引き続きクリティカルセクションを所有します。
その後、スレッド1は実行を開始し、スレッド2を横取りします。スレッド1はスレッド3が所有するクリティカルセクションに入ろうとしますが、別のスレッドが所有しているため、スレッド1はクリティカルセクションを待機します。
その時点で、スレッド2はスレッド3よりも高い優先度を持ち、スレッド1は実行されていないため、実行を開始します。スレッド2は実行を継続するため、スレッド3は、スレッド1が待機しているクリティカルセクションを決して解放しません。
したがって、システムで最も優先度の高いスレッドであるスレッド1は、優先度の低いスレッドが実行されるのを待ってブロックされます。
[仮定、低プロセス= LP、中プロセス= MP、高プロセス= HP]
LPはクリティカルセクションを実行しています。クリティカルセクションに入る間、LPは何らかのオブジェクト、たとえばOBJのロックを取得している必要があります。 LPは現在、クリティカルセクション内にあります。
その間、HPが作成されます。優先度が高いため、CPUはコンテキストスイッチを実行し、HPは現在同じクリティカルセクションではなく、他のコードを実行しています。 HPの実行中のある時点で、同じOBJにロックが必要です(同じクリティカルセクションにある場合とない場合があります)が、OBJのロックは、クリティカルセクションの実行中に横取りされたため、LPによって保持されます。プロセスが実行中ではなく準備完了状態にあるため、LPは現在放棄できません。これで、HPはBLOCKED/WAITING状態に移行します。
ここで、MPが入り、独自のコードを実行します。MPはOBJのロックを必要としないため、正常に実行を続けます。HPはLPがロックを解除し、LPがMPの実行を終了してLPがRUNNING状態に戻るまで待機します(ロックを実行して解除します)。準備完了(そして、優先度の低いタスクを横取りして実行中になります。)
つまり、実質的には、MPが終了するまで、LPは実行できず、したがってHPは実行できません。したがって、HPは、OBJロックを介して直接関連していないにもかかわらず、MPを待機しているようです。->優先順位の逆転。
優先順位逆転の解決策は、 Priority Inheritance -
プロセス(A)の優先度を、Aがリソースロックを持っているリソースを待機している他のプロセスの最大優先度に上げます。
非常にシンプルで明確にさせてください。 (この回答は上記の回答に基づいていますが、鮮明な方法で提示されています)。
リソースR
と3つのプロセスがあるとします。 L
、M
、H
。ここで、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
は実行されません。時間が重要なアプリケーションでは危険な場合があります
ソリューションについては、上記の回答を参照してください:)
優先順位の逆転とは、優先順位の低いプロセスが、優先順位の高いプロセスが必要とするリソースを取得し、リソースが解放されるまで優先順位の高いプロセスが進行しないようにすることです。
例:FileAは、Proc1およびProc2からアクセスする必要があります。 Proc 1はProc2よりも高い優先順位を持っていますが、Proc2は最初にFileAを開くことができます。
通常、Proc1はProc2の10倍の頻度で実行されますが、Proc2がファイルを保持しているため何もできません。
そのため、Proc1がProc2がFileAで終了するまでブロックし、Proc2がFileAのハンドルを保持している間、基本的にそれらの優先順位は「逆転」します。
「問題の解決」に関する限り、優先順位の逆転は、それが発生し続ける場合、それ自体が問題です。最悪の場合(ほとんどのオペレーティングシステムではこれは起こりません)、Proc1が実行されるまでProc2の実行が許可されなかった場合です。これにより、Proc1は割り当てられたCPU時間を取得し続けるため、システムがロックされ、Proc2はCPU時間を取得しないため、ファイルは解放されません。
優先順位の逆転は次のように発生します。名前が高、中、低の優先順位を表すプロセスH、M、およびLを考えると、HとLのみが共通のリソースを共有します。
たとえば、Lは最初にリソースを取得し、実行を開始します。 Hもそのリソースを必要とするため、待機キューに入ります。 Mはリソースを共有せず、実行を開始できるため、共有します。 Lが何らかの手段で割り込まれた場合、Mは優先順位が高く、割り込みが発生した瞬間に実行されるため、Mは実行状態になります。 HはMよりも高い優先順位を持っていますが、待機キューにあるため、リソースを取得できず、Mよりも低い優先順位を意味します。Mが終了すると、Lは再びCPUを引き継ぎ、Hをずっと待機させます。
優先度の高いH
と優先度の低いL
の2つのプロセスがあるシステムを考えます。スケジューリングルールは、H
が高い優先度のために準備状態にあるときはいつでも実行されるというものです。 L
がクリティカル領域にある特定の瞬間に、H
の実行準備が整います(たとえば、I/O操作が完了します)。 H
はビジー待機を開始しますが、L
の実行中にH
がスケジュールされることはないため、L
はクリティカルセクションを離れることができません。したがって、H
は永久にループします。
この状況はPriority Inversion
と呼ばれます。優先度の高いプロセスが優先度の低いプロセスで待機しているためです。
優先度の高いプロセスが、優先度の低いプロセスまたは優先度の低いプロセスのチェーンによって現在アクセスされているカーネルデータを読み取りまたは変更する必要がある場合、スケジューリングの課題が発生します。通常、カーネルデータはロックで保護されているため、優先順位の高いプロセスは、優先順位の低いプロセスがリソースを使い果たすまで待つ必要があります。優先度の低いプロセスが優先度の高い別のプロセスに優先して優先される場合、状況はより複雑になります。例として、L、M、Hの3つのプロセスがあり、それらの優先順位はL <M <Hの順序に従っていると仮定します。プロセスHにはプロセスRが現在アクセスしているリソースRが必要であると仮定します。リソースRを使用してLが終了するのを待ちます。ただし、プロセスMが実行可能になり、プロセスLがプリエンプションになったと仮定します。この問題は優先順位の逆転として知られています。2つ以上の優先順位を持つシステムでのみ発生するため、2つの優先順位のみを持つという解決策があります。ただし、ほとんどの汎用オペレーティングシステムでは不十分です。通常、これらのシステムは優先度継承プロトコルを実装することで問題を解決します。このプロトコルによれば、優先度の高いプロセスが必要とするリソースにアクセスしているすべてのプロセスは、問題のリソースが終了するまで高い優先度を継承します。終了すると、優先順位は元の値に戻ります。上記の例では、優先度継承プロトコルにより、プロセスLがプロセスHの優先度を一時的に継承し、プロセスMがその実行を横取りすることを防ぐことができます。プロセスLがリソースRを使用して終了すると、Hから継承された優先度を放棄し、元の優先度になります。リソースRが使用可能になったため、MではなくプロセスHが次に実行されます。参照:アブラハムシルバーシャッツ
ブロックされた高優先度のスレッドがリソースを保持している低優先度のスレッドに高優先度を転送する場合、優先度の反転を回避できます。