目次
セマフォ機構
序文:
- ダブルフラグチェックファースト方式では、エリアに入る「チェック」と「ロック」が一度に完了できず、2つのプロセスが同時にクリティカルエリアに入る事態が発生する可能性があります。
- プロセスの相互排除のすべての実装は、待機する権利を実現できません
- 1965 年、オランダの学者 DiJkstra は、プロセスの相互排除と同期を実現する効果的な方法、つまりセマフォ機構を提案しました。
セマフォの意味
セマフォ:セマフォは実際には変数です (整数またはより複雑なレコード変数にすることができます). セマフォは、システム内の特定のリソースの数を表すために使用できます. たとえば、システムにはプリンターが1つしかありません.初期値 1 でセマフォを設定できます
知らせ:
- ユーザープロセスは、オペレーティングシステムが提供するプリミティブのペアを使用してセマフォ上で動作することができ、プロセスの相互排除とプロセスの同期を便利に実現します。
- プリミティブのペア: wait(S) プリミティブと signal(S) プリミティブ。プリミティブは自分で作成した関数として理解できます。関数名はそれぞれ wait と signal です。括弧内のセマフォ S は実際には関数呼び出し A です。渡されたパラメーター (システムによって提供されるプリミティブのペアを使用して、セマフォを操作できます)
- 待機およびシグナル プリミティブは、略して P および V 操作と呼ばれます。したがって、wait(S) と signal(S) の 2 つの操作は、しばしば P(S) および V(S) と書かれます; セマフォ S に対する P 操作は、プロセスがこのタイプのリソースのユニットを要求することを意味します。セマフォ S に対する P 操作 V 操作の実行は、プロセスがこのタイプのリソースのユニットを解放することを意味します。
整形セマフォ
意味:整数セマフォを使用して、システム内の特定のリソースの数を表す
例:コンピュータにはプリンタがあります
理解:スレッドが実行されると、wait(S) が最初に実行されます。このとき、別のスレッドが入ってくると、S<=0 が true であるため、プロセスが signal(S) の実行を終了するまでループし続けます。セマフォ
注:プロセス (P1) が一時的にクリティカル エリアに入ることができない場合、システム リソースが十分でない場合、プロセッサは常に占有され、継続的なチェックにより、待機する権利が満たされないビジー待機が発生します。
記録セマフォ
序文:プラスチックセマフォのビジー待ちの問題を解決するために
意味:レコード データ構造によって表されるセマフォ
理解:スレッドが実行されると、最初に wait(S) が実行されます. このときに別のスレッドが入ってきた場合、残りのリソースの数が <0 の場合、プロセスは実行中の状態からブロック状態になります (セマフォを占有する前に)セマフォ S の待ち行列 L に移動し、前のプロセスがシグナル (S) を実行してセマフォを解放するまで、プロセスは起こされません。
セマフォでプロセスの相互排除を実現
具体的なプロセス
- 並行プロセスの主要なアクティビティを分析し、重要なセクションを明確にする
- 相互排除セマフォミューテックスを設定、初期値は1(クリティカルセクションでアクセスできるリソースは1つだけのため)
- クリティカルセクションの前に P(mutex) を実行する
- クリティカルセクションの後に V(mutex) を実行する
知らせ:
- 重要なリソースごとに異なるセマフォを設定する必要があります。
- P 操作と V 操作は同時に発生する必要があります。P がないと重要なリソースへの相互排他的アクセスが保証されず、V がないとリソースが解放されず、待機中のプロセスが起動されません。
セマフォ機構によりプロセス同期を実現
プロセスの同期:各並行プロセスを必要に応じて整然と進行させる
実施プロセス
- どこで「同期関係」を実現する必要があるかを分析します。つまり、2 つの操作が並行して実行されるようにする必要があります。
- 同期セマフォSを設定、初期値は0
- 前の操作の後に V(S) を実行する
- ポスト操作の前に P(S) を実行する
理解:コード 2 をコード 4 の前に実行する場合は、最初のセマフォが 0 であるため、最初に V 操作を実行してセマフォを 1 に変更し、次に P 操作を実行してセマフォを 0 に変更してから、次のピースを実行します。コードの (S= 0 のため、最初に P 操作を実行することはできません。P が最初に実行されると、直接ブロックされ、V 操作が実行された後に起床します)
セマフォは先行関係を実装します
実施プロセス
- 先行関係のペアごとに同期変数を設定するには
- 対応する同期変数は、「前操作」の後に V 操作を実行します。
- 対応する同期変数は、「事後操作」の前に P 操作を実行します。
理解:多層同期関係に相当します。
生産者消費者問題
具体操作
序文:システムには生産者プロセス群と消費者プロセス群があり、生産者プロセスは毎回1つの製品を生産してバッファに入れ、消費者プロセスはバッファから製品を1つ取り出して使用する(注: ここでの製品は、ある種のデータとして理解されます) プロデューサーとコンシューマーは、サイズ n の最初は空のバッファーを共有します
知らせ:
- バッファーがいっぱいでない場合にのみ、プロデューサーは製品をバッファーに入れることができます。それ以外の場合は待機する必要があります (同期関係)。
- バッファが空でない場合、消費者はそこから製品を取り出すことができます。それ以外の場合は待機する必要があります (同期関係)
- バッファーは重要なリソースであり、各プロセスは相互に排他的なアクセス (相互排他関係) を持つ必要があります。
emptyとmutexPVの操作順序を変更
理解:この時点でバッファーが製品でいっぱいの場合、empty=0、full=n; 生産者は製品を生産し、1 がロックされ、2 バッファーがなくなり、バッファーに入ることができないことがわかります。ブロック; コンシューマーに関して言えば、P はロックされて解放されていないため、直接入ることはできません (プロデューサーには V(空) が必要、コンシューマーには P(ミューテックス) が必要 - 互いのリソースを待ち、デッドロック) )
結論:デッドロックが発生しないように、相互排他を実装する P 操作は、同期を実装する P 操作の後である必要があります
複数の生産者と複数の消費者の問題
例:テーブルの上に皿があり、果物は一度に 1 つだけ置くことができます; 父親は娘に食べさせるためにリンゴを置きます; 母親は息子にオレンジを置きます. 皿が空のときだけ果物を置くことができます; あるときだけ.果物の必要な皿の上の何かは、息子と娘によってのみ消費されます
分析する
相互排他関係 (mutex=1):バッファへのアクセスは相互に排他的でなければなりません
シンクロ関係(一前後)
- 父がりんごを入れ、娘が取る
- お母さんがみかんを入れて、息子がそれをとります
- 両親は皿が空の場合にのみ果物を置くことができます
埋め込む
注:ここでは、P(mutex) と V(mutex) を省略できます (プレートが 1 つしかないため、父親はそれを消費し、母親は当然それを消費できません [P(mutex) 操作を省略します]; そして父と娘、母と息子は同期関係 [V(mutex)操作を省略])
喫煙者問題
3 つのスモーカー プロセスと 1 つのサプライヤー プロセスを持つシステムがあるとします. 各スモーカーはタバコを巻いて喫煙し続けますが, タバコを巻いて喫煙するには, タバコ, 紙, 接着剤の 3 つの材料が必要です. 3 人の喫煙者のうち、1 人目はタバコ、2 人目は紙、3 人目は接着剤を所有しています。サプライヤープロセスは3つの材料を無期限に提供し、サプライヤーは毎回2つの材料をテーブルに置き、残りの材料を持っている喫煙者はタバコを巻いて喫煙し、サプライヤープロセスにシグナルを送信して終了したことを伝えます。テーブルの上に別の 2 つの材料があり、このプロセスが繰り返されています (供給者の目的: 喫煙者が交代で喫煙します)。
3つの組み合わせ
- 組み合わせ 1:紙 + のり
- 組み合わせ 2:タバコ + 接着剤
- 組み合わせ 3:タバコ + 紙
同期関係
- テーブルに組み合わせ 1 があります: 最初の喫煙者がそれを受け取ります
- テーブルのコンボ 2: 2 番目の喫煙者が取ります
- テーブルのコンボ 3: 3 番目の喫煙者がそれを取る
- シグナル完了: サプライヤーは次の組み合わせをテーブルに置きます
リーダーの問題
前書き:ファイルを共有するリーダーとライターの 2 つの並行プロセスがあります. 2 つ以上の読み取りプロセスが同時に共有データにアクセスする場合、副作用は発生しませんが、書き込みプロセスと他のプロセスが共有データに同時にアクセスすると、副作用は発生しません。同時にデータの不整合につながる可能性のある状況
したがって、必要
- 複数のリーダーがファイルに対して同時に読み取り操作を実行できるようにする
- ファイルに情報を書き込むことができるライターは 1 人だけです
- ライターは、書き込み操作が完了するまで、他のリーダーまたはライターの動作を許可しません
- ライターが書き込み操作を実行する前に、既存のすべてのリーダーとライターを終了する必要があります
潜在的な問題:読み取りプロセスがまだ読み取り中の場合、書き込みプロセスはブロックして待機する必要があり、「餓死」する可能性があります。したがって、このアルゴリズムでは読み取りプロセスが優先されます
理解:リーダー プロセスがファイルを読み取ると、新しいライター プロセスが到着します。最初のリーダー プロセスは既に V(w) を実行しているため、ライター プロセスは P(w) 操作を実行してもブロックされません。P を実行するとき(rw) 操作の場合、最初のリーダー プロセスが既に P(rw) に対して P 操作を実行しているため、ライター プロセスはこの位置でブロックされます; この時点で 2 番目のリーダー プロセスが到着すると、前のライター プロセス P (w)、V(w) を実行しないため、リーダー プロセスは P(w) でブロックされます。
コア アイデア:現在共有ファイルにアクセスしている読み取りプロセスの数を記録するカウンター カウントを設定します。カウント値を使用して、現在入っているプロセスが最初の読み取りプロセスか最後の読み取りプロセスかを判断し、さまざまな処理を行うことができます。
食の哲学者問題
円卓に 5 人の哲学者が座っており、2 人の哲学者の間に箸が置かれ、テーブルの真ん中にご飯が置かれています。哲学者は自分の人生を考えることと食べることに専念し、哲学者は考えるときに他の人に影響を与えません。哲学者はお腹が空いたときだけ、左右の箸を(1本ずつ)手に取ろうとしますが、箸がすでに他の人の手にある場合は、待つ必要があります。腹を空かせた哲学者は、二本の箸を手に取ってからしか食べられない. 食事が終わったら、箸を置いて考え続ける.
前書き:セマフォ設定、相互排他的セマフォ配列の定義 chopstick[5] ={1,1,1,1,1} は、5 本の箸への相互排他的アクセスを実現するために使用され、哲学者には 0-4 の番号が付けられます, 箸哲学者 i の左側には i 番号が付けられ、右側の箸には (i+1) 番号が付けられます%5
主な問題:デッドロックの解決、相互排除セマフォ ミューテックスの追加
モニター
パイプラインを導入する理由
セマフォ メカニズムの問題:プログラミングが難しく、エラーが発生しやすい
モニターの定義と基本特性
モニターは、これらのパーツで構成される特別なソフトウェア モジュールです。
- モニターにローカルな共有データ構造
- データ構造を操作する一連の手続き
- モニターに対してローカルな共有データの初期値を設定するステートメント
- モニターには名前が必要です
チューブの基本特性
- モニターにローカルなデータには、モニターにローカルなプロセスのみがアクセスできます
- プロセスは、モニターでプロセスを呼び出すことによってのみ、共有データにアクセスするためにモニターに入ることができます
- 一度に 1 つのプロセスのみがモニターで内部プロシージャを実行できます
理解: 2 つのコンシューマが最初に実行される場合、プロデューサ プロセスは後で実行されます。次に、最初のコンシューマ プロセスが実行時にモニタの remove メソッドを呼び出し、この時点でバッファに利用可能な製品があるかどうかを最初に判断します。 、その後、空の条件変数に関連するキューで待機します; 同様に、2 番目のコンシューマー プロセスが remove を実行し始めると、count の値が 0 であることもわかり、空の条件変数が終了するのを待ちます。キュー; その後、生産者プロセス Start が挿入関数を実行し、自身の製品をバッファーに入れ、入れた製品がバッファー内の最初の製品であるかどうかを確認します。 , これは、私の製品を待っている他の消費者プロセスが存在する可能性があることを意味します. そのため、空のキューでプロセスをウェイクアップします. 最初のプロセスがウェイクアップされた後、count-- の実行を開始します. The buffer is full before the product. バッファーがいっぱいの場合は、signal(full) で起動する必要があるプロデューサー プロセスが存在する可能性があることを意味し、プロダクト ポインターを返してプロダクトを取り出します。
知らせ:
- 各プロセスが相互に排他的にモニターにアクセスする必要がある機能は、コンパイラーによって実装されます。
- 条件変数と待機/ウェイク操作をモニターに設定して、同期の問題を解決できます
デッドロック
意味: 2 つのスレッドが互いに必要なリソースを保持し、互いの実行結果を待ち、膠着状態を形成し、どちらのスレッドもリソースを解放しません
飢餓:必要なリソースへのアクセスが長期間欠落しているために、プロセスが前進できない状態
デッドロックの必要条件
- 相互排除条件:相互に排他的でなければならないリソースの競合のみがデッドロックを引き起こす可能性があります
- リクエストと保留の条件:プロセスはリソースのリクエストをブロックし、取得したリソースを保留します
- 譲渡不可能な状態:プロセスはリソースを取得しており、それが使い果たされるまで剥奪することはできません
- ループ待ち状態:複数のプロセス間で頭尾ループ待ちリソース関係が形成されている
知らせ:
- デッドロックが発生すると必ず循環待ちが発生するが、循環待ちが発生するとデッドロックにならない場合がある
- 譲れないリソースを不当に割り当てると、デッドロックが発生する可能性があります
特定のケース
public class DeadLock {
public static void main(String[] args) {
Makeup g1 = new Makeup(0, "灰姑娘");
Makeup g2 = new Makeup(1, "白雪公主");
g1.start();
g2.start();
}
}
class Lipstick{}
class Mirror{}
class Makeup extends Thread{
//需要的资源只有一份
static Lipstick lipstick=new Lipstick();
static Mirror mirror=new Mirror();
int choice;
String girlName;
Makeup(int choice,String girlName){
this.choice=choice;
this.girlName=girlName;
}
@Override
public void run() {
//化妆
try {
makeup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void makeup() throws InterruptedException {
if (choice==0){
synchronized (lipstick){
System.out.println(this.girlName+"获得口红的锁");
Thread.sleep(1000);
synchronized (mirror){
System.out.println(this.girlName+"获得镜子的锁");
}
}
}else {
synchronized (mirror){
System.out.println(this.girlName+"获得镜子的锁");
synchronized (lipstick){
System.out.println(this.girlName+"获得口红的锁");
}
}
}
}
}
デッドロック処理戦略
- デッドロックを防ぐには、デッドロックに必要な 4 つの条件のうち 1 つ以上を破棄します。
- デッドロックを回避し、システムが何らかの方法で危険な状態にならないようにして、デッドロックを回避します。
- デッドロックの検出と除去により、デッドロックが発生する可能性がありますが、オペレーティング システムはデッドロックの発生を検出し、デッドロックを除去するための何らかの措置を講じます。
デッドロック防止
ミューテックス状態を破る
相互排除条件:相互に排他的でなければならないリソースの競合のみがデッドロックを引き起こす可能性があります
相互に排他的にしか使用できないリソースを共有して使用できるように変更すると、システムがデッドロック状態になることはありません。
たとえば、次の例に示すように、オペレーティング システムは SPOOLing テクノロジを使用して、専用デバイスを共有デバイスに論理的に変換できます。
プロセス:各プロセスからプリンターに送信された要求は、最初に出力プロセスによって受信され、それらの要求が受信されると、これらのプロセスは他のことをスムーズに実行できます; その後、出力プロセスは各プロセスの要求に基づいて、Putプリンターで印刷する
短所:すべてのリソースを共有使用のリソースに変換できるわけではありません。そして、システムのセキュリティのために、このような相互排除は多くの場所で保護されなければならないため、多くの場合、相互排除の条件は破ることができません。
譲れない条件の違反
非譲渡条件:プロセスによって取得されたリソースが使い果たされる前に、それらは他のプロセスによって強制的に奪われることはなく、アクティブに解放されることしかできません。
不可譲条件プログラムの弱体化
- シナリオ 1:プロセスが新しいリソースを要求し、満足できない場合、彼 (プロセス) は保持されているすべてのリソースをすぐに解放し、将来必要になったときに再度適用する必要があります。つまり、一部のリソースが使い切られていない場合でも、それらを積極的に解放する必要があり、譲渡不可能な状態を破る
- 解決策 2:特定のプロセスが必要とするリソースが他のプロセスによって占有されている場合、オペレーティング システムは必要なリソースを強制的に奪うのを支援できます。この方法は、一般的に各プロセスの優先度を考慮する必要があります(優先度の高いプロセスにプロセッサのリソースを強制的に奪う deprivation スケジューリング法など)。
欠点
- 実装がより複雑
- 解放によって得られたリソースは、前の段階の作業を無効にする可能性があるため、この方法は通常、CPU などの状態の保存と復元が容易なリソースにのみ適しています。
- リソースの適用と解放を繰り返すと、システムのオーバーヘッドが増加し、システムのスループットが低下します。
- オプション 1 が採用された場合、特定のリソースが一時的に利用できない限り、以前に取得したリソースを放棄して後で再適用する必要があることを意味します。これが常に発生すると、プロセスの枯渇につながります
リクエストを破棄して条件を保留する
リクエストと保留の条件:プロセスはリソースのリクエストをブロックし、取得したリソースを保留します
静的割り当て方法を使用できます。つまり、プロセスは実行前に必要なすべてのリソースに適用され、リソースが満たされない限り動作しません。運用が開始されると、これらのリソースは常に彼が所有し、プロセスは他のリソースを要求しません。
短所:一部のリソースは短時間しかかからない場合があるため、プロセスがプロセス全体ですべてのリソースを保持する場合(一部のリソースは頻繁に使用されない)、リソースの重大な浪費が発生し、リソースの使用率が非常に低くなります。さらに、この戦略により、一部のプロセスが枯渇する可能性もあります
ブレークループ待ち状態
循環待ち状態:プロセスリソースの循環待ちチェーンがあり、チェーン内の各プロセスによって取得されたリソースは、次のプロセスによって同時に要求されます。
順次リソース割り当てを使用できます。最初にシステム内のリソースに番号を付け、プロセスが番号の昇順でリソースを要求する必要があり、同じタイプのリソース (同じ番号のリソース) を一度に適用できることを規定します。
原則:プロセスがすでに少数のリソースを占有している場合にのみ、プロセスは多数のリソースを申請できます。このルールに従うと、すでに多数を保持しているリソースプロセスが戻ってきて、逆に少数のリソースを申請することは不可能であるため、循環待ちは発生しません。
デッドロックを避ける
安全な順序:システムがこの順序に従ってリソースを割り当てる場合、各プロセスを完了することができます. 安全な順序が見つかる限り、システムは安全な状態にあります. もちろん、セキュリティ シーケンスには複数の
銀行家のアルゴリズムの核となる考え方:リソース割り当ての前に、割り当てによってシステムが安全でない状態になるかどうかを事前に判断して、リソース割り当て要求に同意するかどうかを決定します (安全でない状態になる場合)。 , このリクエストを一時的に拒否します. プロセスをブロックして最初に待ちます)
例:システムには P0 ~ P4 の 5 つのプロセスがあり、R0 ~ R2 の 3 種類のリソースがあり、初期数量が (10, 5, 7) である場合、ある瞬間の状況を表すことができます。
知らせ:
- このとき合計(7,2,5)が割り当てられ(3,3,2)が残る
- 残りの使用可能なリソース (3、3、2) が各プロセスのニーズを満たすかどうかを順番に確認します
- 残りの使用可能なリソースを、タスクを完了することができるプロセスに割り当てます. プロセスが実行されると、システムがより安全な状態になるように、リソースが解放されます (借りる必要が少なく、返すことができるプロセスを見つけてみてください.タスクを完了した後、より多くのリソース)
- 安全なシーケンスの割り当て: {P1, P3, P0, P2, P4} (1 つだけ、複数ある場合があります)
銀行家のアルゴリズムの手順
- このアプリケーションが、以前に宣言されたニーズの最大数を超えているかどうかを確認します
- この時点で、システムの残りの利用可能なリソースがこの要求を満たすことができるかどうかを確認してください
- 割り当てを試みる、データ構造を変更する
- セキュリティ アルゴリズムを使用して、この割り当てによってシステムが危険な状態になるかどうかを確認します
セキュリティ アルゴリズムの手順
- 現在残っている使用可能なリソースがプロセスの最大需要を満たすかどうかを確認し、そうであれば、プロセスをセキュリティ シーケンスに追加し、プロセスによって保持されているすべてのリソースを再利用します。
- このプロセスを連続して繰り返し、最終的にすべてのプロセスをセキュリティ シーケンスに追加できるかどうかを確認します。
デッドロックの検出と解決
デッドロックの検出と解決のアルゴリズム
- デッドロック検出アルゴリズム:システムの状態を検出して、システムでデッドロックが発生しているかどうかを判断するために使用されます。
- デッドロック解放アルゴリズム:システムでデッドロックが発生したと判断された場合、このアルゴリズムを使用してシステムをデッドロック状態から解放できます。
システムにデッドロックが発生しているかどうかを検出するため
- リソース要求と割り当て情報を保存するために、ある種のデータ構造を使用する
- 上記の情報を使用して、システムがデッドロック状態に入ったかどうかを検出するアルゴリズムを提供する
デッドロック検出
プロセスが必要なリソースを要求した後は、すべてのリソースを解放し、リソースを適用しません. この方法に従って最終的にすべてのエッジを削除できれば、グラフは完全に単純化されていると言えます. この時点でデッドロックがあってはなりません (安全なシーケンスを見つけることに相当します); 最終的にすべてのエッジを除去できない場合、この時点でデッドロックが発生します (エッジにまだ接続されているプロセスはデッドロック状態にあります) )
デッドロックを解消する方法
- リソースの剥奪方法:いくつかのデッドロック プロセスを一時停止 (一時的に外部メモリに置く) し、そのリソースを占有し、これらのリソースを他のデッドロック プロセスに割り当てます。ただし、リソース不足のために中断されたプロセスが長時間にわたって枯渇するのを防ぐ必要があります。
- キャンセル プロセス メソッド:デッドロックされたプロセスの一部またはすべてを強制的にキャンセルし、これらのプロセスからリソースを奪います。このアプローチの利点は、実装が簡単なことですが、代償が高くつく可能性があります。一部のプロセスは長時間実行されていて終了間近である可能性があるため、それらが終了すると、不十分になり、最初からやり直す必要があると言えます。
- プロセスのロールバック方法:デッドロックを回避するために、1 つ以上のデッドロック プロセスを十分にロールバックさせます。これには、システムがプロセスの履歴情報を記録し、復元ポイントを設定する必要があります。