スレッドの作成と優先順位

これまで、何度かマルチスレッドプログラミングを扱ってきましたが、改めてマルチスレッド(メインのスレッド以外に作成するワーカースレッド)関連のWin32API をまとめてみましょう。

今回は、スレッドの作成とスレッドに「優先順位」を設定するAPIを見てみます。

スレッドの作成

スレッドの作成にはCreateThreadを使います。この関数は以下のような形です。

  HANDLE CreateThread(
      LPSECURITY_ATTRIBUTES lpThreadAttributes, 
      DWORD dwStackSize, 
      LPTHREAD_START_ROUTINE lpStartAddress, 
      LPVOID lpParameter, 
      DWORD dwCreationFlags, 
      LPDWORD lpThreadId 
); 

まず、lpThreadAttributes はNTで使用するセキュリティ関連の設定で、Windows95/98 ではNULLにします。次のdwStackSizeではスレッドが使用するスタックの大きさを指定できますが、通常は0にしてデフォルトのまま使う事になるでしょう。
次のlpStartAddress が最も大切な引数です。この引数には、スレッドで実行したい処理を記述した関数を指定します。新規に作成したスレッドは起動されるとこの関数を実行し、すでにあるアプリケーションのメインスレッドとともにマルチスレッドで動作するわけです。この関数に引数を渡したい時には、lpParameterにそのアドレスを指定してください。次のdwCreationFlags はスレッドが作られた時の状態を設定する引数で、CREATE_SUSPEND にするとスレッドは停止した状態で作成され、0だとスレッドが生成されるとすぐに実行が開始されます。
最後の引数はスレッドIDを格納する変数のアドレスですが、スレッドIDを使う必要がなければ適当なDWORD型変数を定義してそのアドレスを渡しておきましょう。

スレッドが実行する関数は、以下の形で定義します。CreateThreadでスレッドを作ると、そのスレッドはこの関数を実行し関数が終わるとスレッドも終了する(ただし、ハンドルを閉じるまではスレッドオブジェクトがシステムに残る)わけです。

  DOWRD WINAPI ThreadFunc(LPVOID);

また、CreateThread はスレッドのハンドルを返すので、このハンドルも保存しておきましょう。スレッドの操作に必要になります。

スレッドの優先順位

スレッドには「優先順位」を設定できます。この優先順位が高いほどそのスレッドに割り当てられる処理時間が長くなるので、早く終えたい並列処理を行うスレッドには高めの優先順を割り当て、逆にアイドル状態の時に行っても良いような処理を行うスレッド(ならわざわざスレッドにする事もないけど)は優先順位を低くすると良いでしょう。
ただし、スレッドに割り当てられる処理時間は、スレッドの優先順位だけでなく、プロセスの「プライオリティ」にも左右されるようです。スレッドの「優先順位」は、システムの中での絶対的な優先順位というよりは、プロセスの中での並列処理における相対的な優先順位という感じになるみたいですね。
スレッドの優先順位を設定するのがSetThreadPriorityで、引数にはスレッドのハンドルと優先順位を指定します。優先順位に指定できるのは、優先順位の高い順に以下の通りです。

  THREAD_PRIORITY_TIME_CRITICAL 
  THREAD_PRIORITY_HIGHEST
  THREAD_PRIORITY_ABOVE_NORMAL
  THREAD_PRIORITY_NORMAL
  THREAD_PRIORITY_BELOW_NORMAL
  THREAD_PRIORITY_LOWEST
  THREAD_PRIORITY_IDLE

プログラム

今回のプログラムは、Javaでの実験と同様に、2つの「数を数えて行く」スレッドを作るマルチスレッドの実験プログラムです。このスレッドは、0から1づつ数を数えていき10000になると終了します。数えている数は、メインウインドウのラベルに表示する事にすると、スレッド関数は以下のようになるでしょう。

  DWORD WINAPI fnThread1(LPVOID lpV) {

      int i;
      char lpszStr[64];

      i=0; /* カウンタ変数クリア */

      while (i<10000) { /* スレッドの終了指示まで */

          i++; /* カウンタを一つ増やす */

          wsprintf(lpszStr,"Thread1 %8d",i);	
          SetWindowText(hwLabel1,lpszStr); /* カウンタの数を表示 */

      }

      return 0;

  }

プログラムでは、スレッド開始ボタンを作り、スレッド開始のボタンをクリックすると二つのスレッドを作るようにしましょう。

  hThread1=CreateThread(NULL,0,fnThread1,0,0,&d); /* スレッド作成 */
  hThread2=CreateThread(NULL,0,fnThread2,0,0,&d);

ただし、二つとも全く同じではつまらないので、スレッド1は高め、スレッド2は低めの優先順位を指定してやります。

  /* スレッドの優先順位設定 */
  SetThreadPriority(hThread1,THREAD_PRIORITY_HIGHEST);
  SetThreadPriority(hThread2,THREAD_PRIORITY_LOWEST);

ボタンをクリックしてスレッドを作ったら、二つのスレッドが数えている値に注目してください。スレッド1の方が速いペースで値が大きくなって行きますね。
スレッドの優先順を変えて、あるいは同時に他の「重い」プログラムを走らせたりプロセスのプライオリティを変えたりして、マルチスレッド処理における各スレッドの実行速度がどうなるか試してみましょう。

プログラムソース表示


Windowsプログラミング実験室 > プログラミング資料庫