プリエンプション
プリエンプション(英: preemption)は、マルチタスクのコンピュータシステムが実行中のタスクを一時的に中断する動作であり、基本的にそのタスク自体の協力は不要で、後でそのタスクを再実行するという意味も含む。このような動作をコンテキストスイッチと呼ぶ。通常、保護されたタスクか、システムの一部であるプリエンプティブスケジューラが行う。それらは、システム内の他のタスクに割り込み、後でそれらタスクを再開させることができる。「プリエンプト」とは「先取りする、差し替える」の意。
ユーザーモードとカーネルモード
[編集]どんなシステム設計でも、プリエンプション不可能な操作が存在する。それは通常カーネルの機能や割り込み処理であり、それらを完了まで実行できるようにしておかないと、競合状態が発生しやすくなり、デッドロックを誘発する。タスクがカーネル機能を処理中は、スケジューラがプリエンプションできないようにすることで、システムの反応性を若干犠牲にするが、カーネル設計を簡略化することになる。システムの特権レベルを指定するCPUモード(ユーザモードとカーネルモード)も、タスクがプリエンプション可能かどうかを判断する基準のひとつとなる。
一部のシステムはプリエンプティブ・カーネル[1]であり、カーネルモードのタスクであってもプリエンプション可能となっている。例えば、Linuxカーネル 2.6 や一部のBSD系がある。
別のシステムは、マイクロカーネル設計で反応性を向上させ、場合によってはプロセスのプリエンプションの必要性そのものを実質的に削減している。実装例としてMach 3.0をリアルタイムに対応させたRT-Machがある。
プリエンプティブ・マルチタスク
[編集]プリエンプティブ・マルチタスク[2]とは、協調的マルチタスクとプリエンプション可能なマルチタスクを区別するための用語である。協調的マルチタスクは、各タスクがシステムリソースを必要としないときにそれを自発的に解放するようプログラムされている方式である。
簡単に言えば、プリエンプティブ・マルチタスクは、割り込み機構を使って現在実行中のプロセスを中断させ、スケジューラを呼び出して次に実行すべきプロセスを決定させる。それによってある一定時間内で、CPU時間は全てのプロセスに(配分はどうであれ)分配される。
プリエンプティブ・マルチタスクでは、オペレーティングシステムのカーネルは優先順位に従ったスケジューリングがなされるようにコンテキストスイッチを自発的に行うこともでき、それが実行中タスクのプリエンプションとなる。高い優先順位のタスクが実行されるように現在実行中のタスクから権限を奪うのが、プリエンプティブ・スケジューリングである。
プリエンプティブ・マルチタスクは、各プロセスに処理時間の「スライス」が割り当てられることをより確実に保証することができる。また新たに重要なデータが到着して、即座にそれを処理するプロセスに通知しなければならないような場合に素早く対応できる。
プロセスは任意の時点で、2つに分類できる。1つは入出力を待っているプロセス(I/Oバウンドと呼ぶ)とCPUを使い続けているプロセス(CPUバウンド)である。初期のシステムでは、プロセスは入力を待っている際にビジーウェイトしていた。その間、プロセスは生産的な作業は全くしていないが、CPUを使い続けていた。割り込みとプリエンプティブ・マルチタスクの発明で、そのようなI/Oバウンドなプロセスはデータが到着するまで「ブロック」または中断/ペンディングされ、他のプロセスがその間CPUを使えるようになった。データが到着すると割り込みが発生し、ブロックされていたプロセス群が即座に実行可能状態に戻される。
メインフレームからシングルユーザーのパーソナルコンピュータ、さらにはユーザーのいない制御システムまで、マルチタスクは様々な理由で便利であるため、オペレーティングシステムの機能として採用されている。マルチタスクは、シングルユーザーにとっては複数のアプリケーションを同時に実行可能とする。
タイムスライス
[編集]「タイムスライス(time slice)」とは、プリエンプティブ・マルチタスクのシステムでプロセスが一度に実行される期間(時間)を意味する。スケジューラはタイムスライス間隔で起動され、次に実行すべきプロセスを選択する。タイムスライスが短すぎると、スケジューラが消費する時間の割合が大きくなるが、逆にタイムスライスが長すぎると、外部イベントに即座に反応できなくなる。
タイムスライスが経過したタイミングでプロセス間の切り替えを行うため、カーネルはタイマーまたはクロック割り込みをスケジュールする。これによって、プロセッサの時間が複数のタスク間で共有分配され、それらが同時並行的に実行されているかのように見せる。このような設計のオペレーティングシステムをマルチタスクOSと呼ぶ。
プリエンプティブ・マルチタスクをサポートしたシステム
[編集]プリエンプティブなオペレーティングシステムとしては、AmigaOS、NEXTSTEP、Windows NT系(XPやVistaを含む)、Windows CE、Linux、BSD系、macOS(iOSを含む)、BeOS、Windows 95/98(32ビットアプリケーションのみ[3])がある。UNIXやその系統のシステム、VMSなどの科学技術計算用や大規模ビジネス用のシステムも古くからプリエンプティブ・マルチタスクをサポートしていたが、高価なライセンス料やハードウェアが必要であったため、一般ユーザーの手に届くものではなかった。また、それらはユーザモードで実行中のスレッドをプリエンプトすることは可能だったが、カーネルモードのスレッドに対するプリエンプトは困難だった。
ノンプリエンプティブ(協調的)オペレーティングシステムの例としては、Windows 1.x, 2.x, 3.x、Windows 95/98(16ビットアプリケーションの場合)、NetWare、Classic Mac OS(System 5.0 以降)がある。マルチタスクでないオペレーティングシステムとしては、古い Classic Mac OS、MS-DOS、コモドール64のOSがあり、一度に1つのプログラムしか実行できない。
AmigaOSは、TRIPOSというプリエンプティブ・マルチタスクシステムに基づいており、一般ユーザー向けに広く利用可能となった初期のプリエンプティブ・マルチタスクシステムであった(1985年)。68000ベースのAmiga上で動作し、仮想記憶ではなかったため、再配置可能なコードブロックによる動的ロード機能を使い、全プロセスを単一のフラットなアドレス空間に置いていた。
初期の IBM PC 用オペレーティングシステムであるMS-DOSやDR-DOSはマルチタスクを全くサポートしていなかった。NetWare、Windows、OS/2がPCに協調的マルチタスクを導入したが、プリエンプティブ・マルチタスクはサポートしていなかった。PCの場合、採用が遅れたのは過去のソフトウェア資産(Intel 8086ベースのPC向けソフトウェア)との互換性を維持する必要があったためである。しかし、Amigaは当初からマルチタスクを考慮して設計されていた。
Windowsで最初に限定的なプリエンプティブ・マルチタスクをサポートしたのはWindows 2.1xでのIntel 80386の仮想86モードを使ったものである。これは、DOSボックスまたは仮想DOSマシン (VDM) と呼ばれる仮想8086マシン上でアプリケーションを動作させるもので、その仮想8086マシンがプリエンプション可能であった。Windows 95とその後継であるWindows 98およびWindows Meでは、32ビットアプリケーションはそれぞれ個別のアドレス空間で実行され、プリエンプション可能だったが、16ビットのアプリケーションは協調的マルチタスクのままだった[3]。Windows NT では最初からプロセスを32ビットアドレス空間で実行し、常にプリエンプティブ・マルチタスクをサポートしていた。これはNT系列のWindowsに引き継がれている(Windows 2000、Windows XP、Windows Vista)。
Classic Mac OSでは、協調的マルチタスクをプリエンプティブ・マルチタスクに改良する計画があったが、Mac OS Xへの移行によって立ち消えとなった。Mac OS XはBSDの流れを汲むDarwinカーネルに基づいており、前身のNEXTSTEPの時代から完全なプリエンプティブ・マルチタスクをサポートしている。
OS/2 Warpは、IBMがマイクロソフトと共同開発したOS/2を改良したもので、386システムをターゲットとして、ネイティブアプリケーションにはプリエンプティブ・マルチタスクをサポートしていた。また、複数のウィンドウセッションをプリエンプティブに実行可能であった。
UNIX系OSでは、Solarisが初めて本格的なプリエンプティブ・カーネルを実現した。その元となったSVR4ではカーネル内に限定的なプリエンプション・ポイントを実装していたが、Solarisではミューテックスなどの軽量なロック機構を用いてカーネル内のデータを保護することにより、カーネルのほぼ全域にてプリエンプションが可能となった。併せて、リアルタイム性が必要なスレッドに対し、(リアルタイム性が不要な)一般のスレッドよりも高い優先度を割り当てるようになった。これらの変更により、リアルタイム性が必要なスレッドはユーザモードでの実行を含め、一般スレッドをカーネルモードにいる場合も含めてプリエンプトできるようになり、応答遅延の改善に貢献した。後に、これらの変更の多くはLinuxや一部のBSD系OSにも実装されている。
RTOSは応答遅延の保証が本来の目的であることから、データ保護などのための最小限の排他制御を除き、カーネル内も含めていつでもタスクをプリエンプトでき、優先度の通りにタスクがスケジュールされるように設計および実装している。目的の都合上、汎用OSとしては制限が厳しい仕様となる場合もある。