今時のOSでは複数のプロセスを同時に動かすことが出来ます。 実際に利用者が使うアプリケーションが一つであっても GUI などの入出力を制御するプロセスが動いていることでしょう。 しかし、実際にそれを動かしている CPU は一つしかありません (最近はメニーコアも当たり前になりましたが)。 一つの CPU で複数のプロセスを動かすための手法について解説します。
単純に言えば一つのコアで複数のプロセスを同時に動かすことは出来ません。 現在の計算機のアーキテクチャでは原理的に不可能なのです。 それではどのように実装しているのかと言うと、 複数のプロセスを交互に実行しているだけなのです。 利用者が気づかないくらいに素早く切り替えれば 実質上同時に動いているとみなせるという仕組みです。 メニーコアでは本当に同時に動いていますが。
各プロセスは少なくとも固有のレジスタ値やその他の実行時情報を持っています。 別のプロセスに切り替える際には 元のプロセスの実行時情報を保存すると共に 新しいプロセスの実行時情報を復帰します。 そうすることによって中断された状態から再度実行するのです。 また OS によってはメモリ空間も独立したものを用意していたり、 別プロセスからメモリを破壊されないように保護していたりします。
プロセスを交替させるスケジューリングに関しては様々な手法があります。 基本的な方針としては、 GUI のような入出力は素早い応答が欲しいので 一回辺りが短くても頻繁に実行する必要がありますし、 動画エンコードのような数値計算は応答が不要なので 頻度は少なくても合計の時間が長くなる必要があります。 CPU が仕事をせずに外部の作業の結果を待つのなら その間に CPU に他の仕事をさせると全体の効率を良くすることが出来ます。
また仕事の実行単位にはスレッドというものもあります。 スレッドも固有のレジスタ値やその他の実行時情報を持っていて 複数のスレッドを切り替えて交互に実行することが出来ます。 プロセスとスレッドの違いは、 プロセスは固有のデータ領域やコード領域を持っているのに対し、 スレッドは実行時情報しか持っていないという点にあります。 一つのプロセスの内部に複数のスレッドが存在して データ領域やコード領域を共有して協調的に動作するのです。
プロセスとスレッドの関係は OS とプロセスの関係に似ていますね。 また一般的にはプロセスが持つ実行時情報というのも 一つのスレッドとして扱うことが出来ます。 この関係を図式化すると以下のようになります。
-
OS
-
プロセス1 - データ領域1 コード領域1
- スレッド1-1
-
プロセス2 - データ領域2 コード領域2
- スレッド2-1
- スレッド2-2
- スレッド2-3
-
プロセス1 - データ領域1 コード領域1
ちなみにプロセス間であっても 共有メモリやファイルシステム、ソケット通信などを経由して 協調的に動作することは出来ますが、 記述が複雑になりがちな上に出来ることにも制限があります。 さらに言えばコンピュータ間でも協調動作することは出来ますが、 プロセス間よりも輪をかけて難しくなります。 その代わりに比較的安価に大規模処理を行うことが出来ます。