同期とクリティカル区間
カーネルを 再入可能(reentrant) にするには、適切な同期機構が必要です。
あるカーネル実行パス(処理)が カーネルデータを利用中に一時停止 した場合、データの整合性が保証されるまで 他のカーネル実行パスが同じデータにアクセスしてはならない というルールがあります。
なぜなら、複数の処理が同じデータを同時に変更すると、情報が破損して 誤動作を引き起こす可能性 があるからです。
競合状態(Race Condition)
競合状態 とは、処理の実行順序によって結果が変わってしまう問題のことです。
以下の例で考えてみましょう。
例:共有資源の管理
あるシステムでは、利用可能な資源の数を記録する変数 を使って、複数の処理が資源を確保する仕組みになっています。
もし、適切な同期が行われていないと、以下のような問題が発生します。
- 処理 A が開始し、資源の数を確認
- 変数の値を読み取り、資源が「1つ残っている」と認識。
- この直後に、処理 B も開始
- A と同じ変数を読み取り、「まだ 1つ残っている」と判断。
- 処理 B が資源を確保
- 変数の値を 1 減らし、資源を使用開始。
- 処理 A も資源を確保しようとする
- しかし、本当はもう資源は残っていないにもかかわらず、A は「まだある」と思い込んでいる。
- そのまま変数の値をさらに 1 減らしてしまう。
- 結果:変数の値が「-1」になり、2つの処理が同じ資源を使用
- 存在しない資源が使われてしまうため、システムが誤動作を起こす可能性がある。
このように、実行タイミングによってシステムの動作が変わってしまう場合、そのコードは競合状態にある といいます。
クリティカル区間(Critical Section)
上記のような競合状態を防ぐためには、データの一貫性が求められる処理を「クリティカル区間」として保護 する必要があります。
クリティカル区間とは?
- 複数の処理が同時に実行されるとデータが破損する可能性がある部分のこと。
- 1つの処理が実行中は、他の処理が同じ区間に入れないようにする必要がある。
たとえば、変数の 読み取りと書き込みをセットで 1 つの操作(アトミック操作) にすることで、競合状態を防ぐことができます。
しかし、カーネルのデータ構造には 1 回の操作ではアクセスできないもの も多くあります。
たとえば、リンクリストから 1 つの要素を削除する 場合、複数のポインタを更新する必要があるため、途中で割り込まれるとデータが壊れてしまう のです。
このような場面では、クリティカル区間を適切に管理するための 同期機構 が必要になります。
カーネル内プリエンプトの禁止
競合状態を防ぐための基本的な方法 として、伝統的な UNIX カーネルの一部は カーネル内プリエンプション(preemption, 途中停止)を禁止 していました。
つまり、カーネルモードで動作中のプロセスは、強制的に停止させられることがない という仕組みです。
メリット
- 単一プロセッサ環境では簡単な解決策となる
- 他のプロセスに切り替わらないため、カーネルのクリティカル区間を安全に実行できる。
デメリット
- マルチプロセッサ環境では不十分
- 異なる CPU で動作する複数の処理が、同じデータに同時にアクセスする可能性がある。
- そのため、プリエンプト禁止 だけでは同期の問題を完全には解決できない。
割り込みの禁止
もう一つの方法として、クリティカル区間に入る前にすべてのハードウェア割り込みを禁止し、クリティカル区間を抜けた後に割り込みを再許可する という手法があります。
メリット
- 割り込みが発生しないため、処理が中断されずに確実に完了できる。
デメリット
- クリティカル区間が長いと、割り込みが長時間禁止されてしまう
- これにより、重要なハードウェア処理(タイマーやデバイス割り込み)が遅延し、システムの応答性が低下する可能性 がある。
セマフォ(Semaphore)
セマフォは、単一プロセッサ・マルチプロセッサの両方で利用できる強力な同期機構 です。
セマフォは、データに関連付けられたカウンタ であり、カーネルスレッドがデータへアクセスする前に必ず確認される仕組み になっています。
セマフォの構成要素
- 整数型変数(カウンタ):リソースの使用可能数を示す。
- 待機プロセスのリスト:セマフォを取得できずにブロックされているプロセスの一覧。
- 2つのアトミック操作
- down()(P 操作): セマフォの値を 1 減らす。
- 値が 0 未満ならば、プロセスは実行を停止し、待機リストに追加される。
- up()(V 操作): セマフォの値を 1 増やす。
- 待機リストにプロセスがあれば、1 つを解除し実行を再開する。
免責事項
本記事は、筆者の理解に基づいて執筆したものです。正確性には十分配慮していますが、内容の誤りや最新の情報と異なる可能性があります。
本記事の内容を参考にしたことによるいかなる損害についても、筆者は責任を負いかねますのでご了承ください。
正確な情報や書籍に書かれている根拠等はサポートしませんので、ご自身で公式ドキュメントをお調べください。
よって、この内容をAIの学習データに活用することはおすすめしません。