豊田 孝

 前回はプロセスを取り上げましたので,今回はプロセスと密接な関係にあるスレッドを取り上げます。ご承知のように,プロセスはOSによって作成されます。作成されたプロセスは,処理内容に応じて,いくつかのスレッドを内部で作成します。このような一般的な背景もあり,プロセスはOSの管理単位,スレッドは実行単位,とそれぞれ定義されることが多いようです。しかし,これら2つの定義を一読しても,おそらく,平均的なWindowsユーザーには何のことなのかさっぱり分からないと思います。そこで,今回は,次のような2つの視点から,プロセスとスレッドの関係を具体的に考えます。

  • プロセスはスレッドを作り出す
  • プロセスはスレッドの動きを管理する

 前回はマシン内で作成されているプロセス情報を表示するサンプル・プログラムを紹介しましたから,今回もまず,スレッド情報を収集し,表示してくれるサンプル・プログラムを実行してみましょう。さて,皆さんの環境では,いったいどれくらいの数のスレッドが実行されているのでしょうか。

本日のサンプル・プログラム

図1●サンプル・プログラムの実行結果
図2●「Windows Media Player」のスレッド情報
図3●前回のサンプル・プログラムの「ThreadCount」項目の値に注目
図4●前回のサンプル・プログラムの「PageFaults」項目の値に注目
図5●「ThreadState」項目と「ThreadWaitReason」項目に注目
 それではいつものようにこちらからサンプル・プログラムをダウンロードし,まずは実行してみましょう。私のWindows XP環境では図1[拡大表示]のような結果が返されました。

 ご覧のように,私のWindows XP環境では345個のスレッドが現在実行されています。345という数字はかなり大きな数字ですから,すべてのスレッドに関する情報を収集・表示するのはたいへんな作業になります。そこで,「スレッドはプロセスによって作成される」事実を応用し,特定のプロセス内部で作成されたスレッドに関する情報のみを収集し,表示してみます。ここでは,すべてのWindowsに付属する「Windows Media Player」を起動した後,こちらのサンプル・プログラムを実行し,「Windows Media Player」プロセスの内部で作成されたスレッドを見てみることにしましょう(図2[拡大表示])。

 図2は,Windows Media Playerが内部で作成しているスレッド総数を示しています。表現を変えれば,Windows Media Playerという1つのプロセスが19個のスレッドを内部で作成しているわけです。ご承知のように,Windows Media Playerは選曲された音楽を再生したり,演奏を任意の時点で停止するためのさまざまなグラフィカル・ユーザー・インタフェース(GUI)を提供してくれます。私たちは,GUI経由で目的の指示を送るわけですが,その指示は19個のスレッドのいずれかによって処理されているわけです。便利なGUIを備えるアプリケーションは,時には「重たい」などといわれることがあります。Windows Media Playerはスレッドを19個作成していますから,マシン性能によっては,「重たい」かもしれませんね。以上で「プロセスはスレッドを作り出す」背景はお分かりになったと思います。

 ところで皆さん,Windows Media Playerは19個というスレッドをどのように管理しているのか知りたいと思いませんか? 図3[拡大表示]は「Windows Media Player」を起動した後,前回のサンプル・プログラムを使って取得したものです。画面中央に「ThreadCount」という項目がありますが,その値は19となっています。その通りなのです。Windows Media Playerプロセスは,作り出したスレッドの数をこのようにきちんと管理しているのです。

 前回のサンプル・プログラムが生成するファイル「Win32_Process.htm」の中に「PageFaults」という項目があります(図4[拡大表示])。私のWindows XP環境では20160という数字が表示されています。この数字は,何らかの処理を実行しようとしたときに,対応するコードがメモリー内に存在しなかった回数を示しているのです。コードがメモリー内に存在しなければ,外部にあるページ・ファイルからそのコードを読み込む必要があります。これはメモリーとハードディスク間のデータ転送を意味しますから,パフォーマンスの低下の原因となります。256MBのメモリーを搭載した私のシステム環境では,2万回以上のデータ転送が行われています。正直,かなり「重たい」感じを受けています。ところで皆さん,メモリーとハードディスク間で転送されるコードとは何でしょうか? そうです,それは基本的にスレッドです。

 それでは再び,今回のサンプル・プログラムに戻って,生成するファイル「Win32_Thread.htm」を見てみましょう(図5[拡大表示])。図5では,「ThreadState」と「ThreadWaitReason」という2つの項目に注目してください。「ThreadState」には5という数値が現在入っています。これは,このスレッドが待ち状態に入っていることを示しています。そして,待ち状態に入っている詳しい理由を示しているのが,「ThreadWaitReason」項目なのです。現在この項目には6という数字が入っていますが,これは,PageIn待ちであるという意味を持っているのです。つまり,このスレッドはページ・ファイルからメモリーに転送されるのを待っている,ということなのです。すでに見たように,私の環境では,2万回以上のデータ転送が発生していますから,19個のスレッドの多くがこのような待ち状態にあります。

 以上見てきたように,プロセスとスレッドの間には密接な関係があります。さらに詳しい関係を調べたいときには,こちらの情報を参考にしてください。

サンプル・プログラムの機能と拡張のためのヒント

 本日のサンプル・プログラムは,リスト1のようになっています。今回のサンプル・コードもこれまでのものとまったく変わりません。DMTF標準化団体定義クラスから派生したWin32_Threadというクラスを活用しています。お時間のあるときに,じっくり検討してみるとよいでしょう。

 サンプル・プログラムを起動すると,10個分のスレッドに関する情報が表示されます。報告されるスレッド数を変更したい場合には,ソースコード内の次の部分を自由に変更してみてください。


If iCount = 11 Then
  Exit For
End If

 また,特定のプロセスとスレッドの関係を調査したいときには,次のコードを変更します。


dwProcessID = "368"

 "368"の部分を目的の数値で差し替えます。この数値は,プロセスIDですから,前回のサンプル・プログラムで取得してください。前回の記事を読むと,任意のプロセスのプロセスIDを取得できるようになります。このような作業を繰り返していくと,プロセスとスレッドに関する理解が日々深まっていきます。プロセスとスレッドはこの連載では触れられないその他のプロパティをたくさん持っています。 例えば,書き込み動作回数や書き込みバイト数などといったプロパティがありますが,それらの値が異常に大きい場合,知らぬ間にあちこちに電子メールを送っているかも知れません。ぜひ理解を深めてください。

なお,本日用意した「ListWMPlayerThreads.vbs」サンプル・プログラムは,dwProcessID設定を自動化しています。自動化しているコードを理解し,自分のプログラム内で応用すれば、すべてのプロセスとスレッドの関係を理解することができます。

 本日は以上で終了です。次回またお会いいたしましょう。ごきげんよう!