プロセスその14

プロセスのメモリに関する話題はこのあたりにして、再び焦点をスケジューリングにちょっと戻してみたい。WindowsにおけるThreadの状態遷移は6.5.6(上巻P391~)にまとめられている。Windows 2000/XPが図6-14(上巻P392)、Windows Server 2003が図6-15(上巻P395)に示されている。両者の違いは(上巻P395に有るとおり)遅延レディという新しいステートの追加にあるが、これは本質的な違いではない。

図1(VAX/VMS Internal and Data Structures Version 5.2のFigure 12.6より抜粋)

さて、これがVMSではどうだったか? というのが図1である。これはIDSのFigure 12.6の抜粋であるが、流石にこのままでは訳が判らないので用語を説明しておくと、

  • CUR:CURrent。実際にCPUを利用できている状況。
  • COM:COMputable。実行可能状態で待機している状況。
  • COMO:COMputable Outswapped。実行可能状態ながら、メモリからSwap Outされている状況。
  • CEF:Common Event Flag wait。Common Event Flagと呼ばれるプロセス間同期メカニズムを使った待機状態。
  • LEF/LEFO:Local Event Flag wait/Local Evelt Flag wait Outswapped。Local Event Flagと呼ばれるプロセス「内」同期メカニズムを使った待機状態。LEFOは更にSwap Outされている。
  • HIB/HIBO:HIBernation wait/HIBERernation Outswapped wait。AST(201回目でちょっと出てきた、User Post I/O Routineなどに利用される非同期ルーチン)イベント待ち。HIBOは更にSwap Outされている。
  • SUSP/SUSPO:SUSPend wait/SUSPend Outswapped):プロセス自身が発行する、何らかのイベント待ち。SUSPOは更にSwap Outされている。
  • PFW:Page Fault Wait。ページフォルトが発生し、当該ページをメモリに読み込むための待ち。
  • FPG:Free PaGe wait。Working Set増加時にFree Pageが不足した場合に、必要なページが用意されるまでの待ち。
  • COLPG:COLlided PaGe wait。複数のProcessが同一Pageを共有している状況で、そのPageがPage Faultになった場合の待ち。
  • MWAIT:Mutex WAIT。ここまでに説明した以外の要因での待ち。

となっている。LEF/HIB/SUSPに関してはInswappedとOutswapedで状態が分かれているのに対し、PFW/FPG/COLPGが分かれていないのは、こちらが本質的にはいずれもPage Faultに関連する待ちだから、ということになる。その意味ではMWAITもMWAITOがあっても良さそうだが、これは細かいものを全部個別に分けていたらキリがないので纏めてしまったのであろう。

さて、先のWindowsのスレッド状態遷移と比較すると、一見だいぶ違うようで、実際はかなり近い構造になっていることが判る。図2に、Windowsのスレッド遷移状態の用語にあわせた形で上書きしたものを示すが、まとめてみるとかなり近い事が判る。実際、Windowsのスレッド遷移図は、OSとしてはごく一般的なものと言ってよい。

図2

大きな違いは、VMSにおけるCOM状態が、Windowsではレディとスタンバイの2つに分かれる事だろう。これについては、スレッド対応が必要になったWindowsならでは、の対処と考えると理解がしやすい。例えばWindows環境で、あるProcessとそれに属するスレッド全部がPage In待ちになっていたとする(VMSで言えばPFW状態)。この状態が解消した場合、VMSではその当該Processの実行Contextは一意に決まるが、WindowsではそのProcessが複数Threadを持つから、実行Contextを選択するためにはProcessからThreadを選ばねばならない。ここでもう一段、ラウンドロビンをかますためには状態を分離したほうが得策と考えられるからだ。Process単位のスケジューリングとThread単位のスケジューリングを一緒にするのは、あまり賢明とは言いがたい。

ちなみに初期化の段階がVMSではCOMO(つまり移行)に繋がるのに対し、Windowsではレディに繋がるが、これはProcessの生成(つまりメモリの確保からはじめないといけない)とThreadの生成(つまりProcessは既に存在しており、メモリも確保されている)で前提が違うからで、本質的な違いではないと考えられる。