プロセス管理

1.プロセス

プロセスとは、特定の仕事をするために一連の操作系列を実行することです。 プロセスはタスク(task)とも呼ばれ、 CPU のスケジューリングの対象となる基本単位です。 一般的にプロセスは実行中のプログラムと解釈されます。

プロセスの状態

プロセスは、生成されてから消滅するまでに3つの状態の間を遷移します。

  1. 実行状態
    CPUを使用し実行中の状態。
    実行可能状態のプロセスの中で最も優先順位が高いプロセスが自動的にこの状態になります。

  2. 実行可能状態
    プロセスは実行可能ですが、他の(優先順位の高い)プロセスが実行中のため、 待機している状態
    実行状態のプロセスが割り当て時間(タイムスライス)切れやイベントの発生によって CPU 使用権を取り上げられると(プリエンプション)、この状態になります。 また待ち状態が完了し、プロセスが再起動されると、自動的に実行可能状態になります。

  3. 待ち状態
    入出力待ちなどにより CPU の使用権を与えられても使用できない待ちの状態。

プロセス制御ブロック

プロセスは、システムの内部ではプロセス制御ブロック(PCB:Process Control Block)と呼ばれるデータ構造で表されます。

PCBはPCB識別子、プロセス優先順位、プログラムカウンタ、 レジスタの退避領域などを格納しています。 実行状態でないプロセスは、中断したときの(プログラムカウンタ、レジスタなど) 情報を退避し、実行状態に戻るときこれらの退避情報をもとに、 中断された直前に回復します。

4.コンテキストスイッチ

あるプロセスから他のプロセスへCPU使用権を切替える一連の処理 (ディスパッチとプリエンプションの繰返し)をコンテキストスイッチと呼ぶ。

実行状態にあるプロセスはプロセッサごとに1つです。 他の複数のプロセスは実行可能状態か待ち状態です。 このために、実行可能状態にあるプロセスと待ち状態にあるプロセスに関して、 それぞれ実行可能キュー(CPU使用権が回ってくるのを順番に待つ) と待ち状態キューと呼ばれる PCB のキューが作られる。

5.プロセスの生成と消滅

  1. 生成
    プロセスの生成では、まずPCBやプロセス用の領域を主記憶上に確保し、 PCBの各項目(名前、優先順位、資源の割り付けなど)を設定します。 その後、PCBに対して実行可能キューの最後につなぐ操作が行われる。

    プロセス用の領域は、コード領域、データ領域、スタック領域からなります。 プロセス用の領域を確保するには2通りの方法があり、 1つは親プロセスと子プロセスでコード領域だけを共有し、 データ領域とスタック領域をコピーする方法です。 もう1つは親プロセスと子プロセスでコード領域とデータ領域を共有し、 スタック領域のみをコピーする方法です。

    後述するスレッドを実現する際にも使用されます。

  2. 消滅
    プロセスの消滅は、通常はプロセスが終了した場合に行われるが、 プロセスの異常終了などのように実行途中の場合にも行われることがあります。 実行を終了したプロセスを消滅させる場合には、 単に当該しますプロセスに対応したPCBの領域をシステムに返却するだけでよい。 しかし、実行途中のプロセスを消滅する場合には、 そのプロセスが使用している資源をシステムに返却するために、 その資源に対応した情報を各キューから削除する必要があります。 この処理を行った後で、ようやく当該プロセスに対応した PCBがシステムに返却されプロセスが消滅します。

6.プロセスの中断と再開

  1. 中断
    プロセスの中断とは、 システムの負荷が高くなったときやシステムに障害が発生したときに、 特定のプロセスを実行可能状態から除くためにシステムによって行われることが多い。

    中断されたプロセスは、 システムあるいは他のプロセスによって再開されるまで前に進むことができない。 プロセスの中断が長時間続く場合は、 プロセスが使用している資源を解放しなければならない。

  2. 再開
    プロセスの再開とは、 プロセスが中断した時点の次の命令から再開することを意味します。

7.プログラムの属性

  1. 再入可能
    複数のプロセスが同時に使用することができるプログラム。
    この属性を持つプログラムは、 プログラムが使用するデータ領域がプロセスごとに確保され、 プログラム実行中に自ら(プログラム)の内容を変更することは許されない。 同時に同一のプログラムを使用することにより、 記憶領域の節約や処理効率の向上を図ることができる。

  2. 逐次再使用可能
    一度主記憶にロードされたプログラムを再度ロードすることなく、 再使用できるプログラム。
    逐次再使用可能にするためには、 ルーチン内部で初期値(データ値)を変更した場合、 そのデータ値を初期値に元に戻す必要があります。 また、プログラム使用時点で排他制御が必要となります。

  3. 再使用不能
    プログラムとプログラム自身が使用するデータ領域が独立していない、 かつデータ値を初期値に元に戻す処理がないプログラム。
    このため、複数のプロセスが同時に、または再使用することが不可能です。

8.スレッド

プロセスを効率よく実行するためには、プロセス自体の高速化のみならず、 プロセスの処理の本質(プロセス生成、消滅、コンテキストスイッチなど) に関係しない操作の時間を極力小さくしなければならない。

このため、OSはスレッド(thread) と呼ばれるプロセスの処理の本質とは関係ない操作の時間を、 (並行処理するなどして)小さくするための機構を実現しています。

プロセスの処理の本質とは関係ない部分で細分化された各スレッドは、 制御の流れを表し、実行に必要なレジスタセットとスタックを持つ。 単一スレッドプログラムの実行(制御)の流れは、 一通り(一筆書き)の流れとなります。 一方、多重スレッドプログラムの実行(制御)の流れは、 多重の流れとなります。

ユーザレベル(Javaなどのマルチスレッド機構)で多重スレッドを実現する場合、 スレッドごとにスタックとレジスタを確保し、 スレッドを切り替えるときには、プログラムカウンタ、レジスタの値、 スタックポインタだけを退避、回復すればよい。

スレッドの切り替えはプロセスの切り替えに比べ、システムにかかる負荷が小さい。 また、サーバプログラムを多重スレッドのプロセスとして構成することによって、 クライアントの要求に対し応答性が向上します。

たとえば、クライアントからサーバに対して要求があるたびに、 その要求に対応したスレッドを生成し(本質的な処理)、 そのスレッドにクライアントが要求した処理とクライアントへの結果の応答を任せる (スレッドはプロセスの処理の本質とは関係のない操作、制御を行う)。 このようにすることによって、サーバはスレッドを生成した後、 直ちに他のクライアントの要求を受け付けることができる。

しかし、多重スレッドプログラムを作成するには、 プロセスの持つ資源を排他制御するなど、 単一スレッドにはない問題を考慮する必要があります。

9.マルチプログラミング(マルチタスク)

プロセスはCPU処理と入出力制御が交互に現れる処理の系列と考えることができる。 プロセスの実行は、まず、CPUの処理から始まる。次に入出力処理が続く。 以降は、この順に処理が繰り返され、最終的にCPU処理で実行が完了します。 プロセスが入出力待ちになると、CPUはアイドル状態となります。

マルチプログラミング(multi programming)は、CPUのアイドル時間を減らし、 CPUの利用率向上を目的としています。 このため、複数のプロセスが同時に主記憶上に置かれ、 実行中だったプロセスが待ち状態になると、 すかさず他のプロセスがCPU使用権を奪います。 したがってCPUはアイドル状態になりにくくなります。

マルチプログラミングにおいて、 CPU処理の割合が入出力処理の割合より多いプロセスを CPUバウンドのプロセスと呼ぶ。 逆に入出力処理の割合がCPU 処理の割合より多いプロセスを入出力バウンドのプロセスと呼ぶ。

10.CPUスケジューラ

CPUスケジューラは、実行可能状態にあるプロセスの集合から、 次にCPUを割り付けるプロセスをある基準(スケジューリングアルゴリズム) によって選択します。 選択されたプロセスにCPU 割り付けを行うのはディスパッチャの役目です。

CPUスケジューラがプロセスを選択する場合、 各スケジューリングアルゴリズムの特長を考慮する必要があります。

複数のスケジューリングアルゴリズムを比較する要素として以下のものがあります。

  1. CPU利用率
    システム稼働時間に対するCPUの動作時間。
    CPUの稼働時間は、システムの稼働時間からCPUのアイドル時間を引いた時間です。
  2. スループット
     単位時間当たりにCPUが処理できる仕事量。

  3. ターンアラウンドタイム
    ユーザが処理要求を出してから完了する(出力結果を得る)までの時間。
    各種待ち時間とCPU処理時間の合計で求めることができる。 バッチ処理の性能の基準として使用。

  4. 待ち時間
    プロセスが完了するまでに実行可能キューで費やした時間の合計。

  5. 応答時間
    ユーザが処理要求を出してから最初の応答までに必要とする時間。
    会話型システムやタイムシェアリングシステムの性能の基準として使用。 会話型システムは、 ユーザが求める結果をユーザとコンピュータで会話しながら作り出していくので、 いつ出力が完了(会話が終了)するかはユーザ次第です。

11.スケジューリングアルゴリズム

スケジューリングアルゴリズムは横取り不可能(nonpreemptive)なものと横取り可能 (preemptive)なものに分けることができる。

前者はCPUがあるプロセスに割り付けられると、 そのプロセスが終了するあるいは入出力完了待ちになる(制御がOSに戻る)まで、 他のプロセスにCPUを割り付けることができない。

後者はプロセスが実行中であっても、CPU使用権を奪い取り、 他のプロセスに割り当てることができる。

・ 横取り不可能…到着順方式、SJF方式
・ 横取り可能…優先度方式、ラウンドロビン方式

  1. 到着順方式
    プロセスは優先順位を持たず、実行可能キューに到着したプロセスから CPUを割り付ける。

    この方式では、 処理時間の長いプロセスが先に到着すると平均ターンアラウンドタイムは大きくなり、 逆に処理時間の短いプロセスが先に到着すると平均ターンアラウンドタイムは小さくなります。

    到着順方式は、プロセスの実行可能キューを FIFOキューとして構成することにより実現されます。

  2. SJF(Short Job First)方式
    この方式はCPU処理時間の短いプロセスから順にCPUを割り付ける方式です。 全プロセスの平均ターンアラウンドタイムを最小にします。 しかし、SJF方式を使用する場合、 各プロセスのCPU処理時間が既知でなければならないため、 実際のスケジューリングアルゴリズムとして使用することはできない。

  3. 優先度方式
    優先度方式では、各プロセスに優先度が割り付けられ、 各時点で最も高い優先度を持つプロセスにCPU使用権が回ってくる。 同じ優先度のプロセスは到着順方式などでスケジュールされます。

    各プロセスに割り付けられる優先度は、 システム内部(デッドライン、入出力時間とCPU時間)、 外部(緊急のイベント)の基準によって定義されます。

    優先度方式での問題は飢餓(starvation)と呼ばれる、 プロセス永久待ち状態が発生することです。 つまり、優先度の低いプロセスがいつになっても実行できないことです。 この問題を解決する方法としてエージング(aging)があります。 エージングは長時間システム内に滞在しているプロセスの優先度を徐々に高くする方法です。

  4. ラウンドロビン
    到着順方式とタイムスライス(一定のCPU割り付け時間)を組み合わせた方式。
    タイムシェアリングシステムのために設計された。

    実行中のプロセスは時間(タイムスライス)が満了すると、 実行可能キュー(FIFOキュー)の最後につながれ、 次にCPU使用権が与えれれるまで待つ。

  5. 多重度レベルスケジューリング
    プロセスの特性を考慮し、 その特性ごとに異なったスケジューリングアルゴリズムを採用すること。
    すなわち、実行可能キューを複数のキューに分割し、 各々異なったアルゴリズムでスケジュールします。 たとえば、会話型プロセス集合にはラウンドロビンスケジューリングを、 リアルタイム処理にはイベントドリブンプリエンプションによる優先度方式を採用します。

カーネルのプロセス管理

カーネルはプロセスについて、 主に次のような管理を行ないます。

  1. プロセスの識別

    カーネルは生成されたプロセスに対して PID(Process ID) という番号を昇順にふり識別管理します。 プログラムの実行が終了してもその PID は永久欠番になり、再使用されません。 ただし、PID が最大数を超えるとまた循環して使われます。

    PID の他、メモリ上でのアドレス、プロセスの状態、 実行時間などの情報は、 カーネル内のプロセステーブルに格納され、管理に利用されます。

  2. プロセスのスケジューリング

    スケジューリングとは CPU を割り当てるプロセスを決定したり切り替えることです。
    プロセスにはそれぞれプライオリティ(優先度)があり、 この値を基準にしてスケジューリングが行われます。 プロセスはこのスケジューリングに従い、 実行状態と実行待ちの状態を繰り返しながら、通常は終了へと向かいます。

  3. メモリ管理

    カーネルは、プロセスをどれだけメモリに読み込むかを決めます。 メモリに読みきれないプロセスに対しては2次記憶へのスワッピングが行われます。
    2次記憶に出すことをスワップアウト、 2次記憶からメモリへ戻すことをスワップインと言います。 このメモリ管理によって、実際のメモリサイズよりも大きなプロセスの実行や、 複数のプロセスの効率的な実行が可能になります。

    詳細はメモリ管理を参照してください。