OS 編で、ざっとですが、マルチタスクについて触れました。 ここでは、プリエンティブなマルチタスク OS について、さらに詳しい話をします。
OS 編では、単に「マルチタスク OS」と書きましたが、 なぜ、ここでは「プリエンティブな」という言葉がついているのでしょうか。 それは、「プリエンティブではない」マルチタスク OS があるためです。
プリエンティブではないマルチタスク OS では、 複数同時に実行されるアプリケーションが、 スムーズに同時進行していくために、 アプリケーションの協力を必要とします。 もし、プリエンティブではないマルチタスク OS で、 アプリケーションを同時実行する上で、非協力的なアプリケーションが実行されると、 そのアプリケーションばかりが実行され、他のアプリケーションが、全く動けなくなってしまいます。
Microsoft Windows ファミリーでは、 Windows 3.1、 Windows 95、 Windows 98、 Windows Me が、 プリエンティブではないマルチタスク OS です。
以下、マルチタスク OS とは、 プリエンティブなマルチタスク OS として説明します。
プリエンティブなマルチタスク OS では、 アプリケーションを同時実行する上で、非協力的なアプリケーションが実行されても、 その他のアプリケーションが、全く動けなくなってしまうことはありません。 しかしながら、マルチタスク OS 上で実行されるアプリケーションを作成する場合、 プログラマは、不必要な CPU 資源を浪費しないように意識して、 プログラムを作成する必要はあります。 この辺りのテクニックについては、プログラミングテクニックの領域になってしまいますので、 ここでは割愛します。
マルチタスク OS で、利用者は、 複数のアプリケーションが、同時進行で実行されているように感じます。 しかし、CPU が、実行できるプログラムは、 たった 1 つだけです。 なのに、OS は、どうやって、 複数のアプリケーションを実行させているのでしょうか。
その答えは、ハードウエアタイマーと、割り込みが握っています。
大抵の計算機には、ハードウエアタイマーと呼ばれる、経過時間を制御するためのハードウエアが搭載されています。 これは、日にちや時刻を管理するための、計算機が持っている時計とは別のハードウエアです。 時計のほうは、ハードウエアタイマーと区別するために、カレンダータイマーと呼ばれたりもします。
ハードウエアタイマーは、料理で使うキッチンタイマーと同じような使われ方をします。 つまり、ある特定の時間が経過すると、CPU に時間の経過を教えてくれるというわけです。 CPU への通知方法は、割り込みです。
複数のアプリケーションを実行させるために、この機構を利用します。 つまり、ある一定の時間が経過すると、常に CPU へタイマー割り込みが発生するようにしておくのです。
タスク切替 単位時間 |
アプリケーション #1 |
アプリケーション #2 |
アプリケーション #3 |
|||
#1 |
実行
|
休止 |
休止 |
|||
#2 |
休止 |
実行
|
休止 |
|||
#3 |
休止 |
休止 |
実行
|
|||
#4 |
実行
|
休止 |
休止 |
|||
#5 |
休止 |
実行
|
休止 |
|||
| · · · |
· · · |
· · · |
· · · |
|||
OS は、同時に実行しなければならないアプリケーションのリストと、 現在実行状態にあるアプリケーションを常に覚えています。
ある瞬間では、アプリケーション #1 が実行されていたとしましょう。 CPU へは、ある一定の時間が経過すると、 タイマー割り込みが発生します。 この時、アプリケーション #1 の実行は、一時的に中断されます。 そして、中断されたアプリケーション #1 の実行を再び再開させるために、次に実行しなければならないインストラクションのアドレスを記憶します。
OS は、同時に実行しなければならないアプリケーションのリストを持っているので、 アプリケーション #1 以外に、実行しなければならないアプリケーションは、 アプリケーション #2 と、アプリケーション #3 であることを把握しています。
したがって、記憶している、アプリケーション #2 (何故、実行を再開するアプリケーションが #3 ではなく、 #2 なのかは、この後を読んでください) の実行を再び再開させるために、次に実行しなければならないインストラクションのアドレスから、 CPU の実行が行われるようにして、 タイマー割り込みの処理を終わります。 すると... アプリケーション #1 が実行されていたときに、 一時的に実行を中断されていたアプリケーション #2 の実行が再開されます。
そして、ある一定の時間が経過すると、再びタイマー割り込みが発生します。 この時は、アプリケーション #2 の実行が、一時的に中断され、 中断されたアプリケーション #2 の実行を再び再開させるために、次に実行しなければならないインストラクションのアドレスを記憶して、 休止状態にある、アプリケーション #1、 もしくは、アプリケーション #3 のどちらかの実行を再開しようとします。
この時、アプリケーション #1 を休止状態にしたタイミングのほうが最近なので、 実行を再開するのは、アプリケーション #3 であると判断し、 アプリケーション #3 の実行を再開しようとします。
記憶していた、アプリケーション #3 の実行再開インストラクションのアドレスから CPU の実行が行われるようにして、 タイマー割り込みの処理を終わらせれば、 アプリケーション #3 の実行が再開されます。
そして、ある一定の時間が経過すると、再びタイマー割り込みが発生して... ということを繰り返すのです。
タイマー割り込みの間隔を 10ms の間隔にすれば、 人間の感覚からすれば、 アプリケーション #1、 アプリケーション #2、 アプリケーション #3 は 同時に実行されているように感じます。
ただし、このやり方だけでは、スムーズなマルチタスクは実現できません。 例えば、アプリケーション #1 が、 キーボードからの文字入力を待っていて、 利用者がキーボードから文字を入力しないと、 次のステップに進めないような状態になっていたとします。 このとき、タイマー割り込みで、 アプリケーション #1 を実行するタイミングが回ってきても、 利用者がキーボードから文字を入力しなければ、 アプリケーション #1 は動くことができません。
この様に、あるアプリケーションが、 何かの処理が完了しないと動けないような状態(イベント待ち状態)になったときは、 その他に実行しなければならないアプリケーションの実行を再開するようにするのです。
イベント待ちしているアプリケーションがあったのなら、 その他のアプリケーションが優先的に実行されるようになったことで、 CPU 資源を無駄なく使えるようになったのです。
マルチタスク OS における、 このようなアプリケーション実行の切り替え動作のことをタスク・ディスパッチング (Task Dispatching)と呼びます。 また、タスクディスパッチングを行うためのタイマー割り込みの時間間隔をカンタム・タイム (Quantum Time)と呼びます。