マルチスレッド

んじゃスレッドでも使ってみんべ、ってことでこういうソースを書いてテストしてたわけなんだけど。

#include <windows.h>
#include <stdio.h>

const unsigned DISPLAY_NUM = 100;
const unsigned THREAD_NUM = 32;

DWORD WINAPI thread_func(LPVOID thread_arg)
{
  unsigned num = *(static_cast<unsigned *>(thread_arg));
  printf("enter thread %2d\n", num);

  for(unsigned count=0 ; count<DISPLAY_NUM ; ++count)
  {
    printf("%2d : %4d\n", num, count);
  }

  printf("leave thread %2d\n", num);

  return 0;
}

int main()
{
  DWORD thread_id[THREAD_NUM];
  HANDLE thread_handle[THREAD_NUM];
  unsigned num[THREAD_NUM];

  {
    for(unsigned i=0 ; i<THREAD_NUM ; ++i)
    {
      num[i] = i;
      thread_handle[i] = CreateThread(NULL, 0, thread_func, &(num[i]), 0, &(thread_id[i]));
      printf("%x, %d\n", thread_handle[i], thread_id[i]);
      if(thread_handle[i] == NULL)
      {
        printf("creating thread was failure.\n");
        return 1;
      }
      if(SetThreadPriority(thread_handle[i], i%2) == 0)
      {
        printf("changing thread priority was failure.\n");
        return 1;
      }
    }
  }

  return 0;
}

何故か意図したどおりの結果が出ない。"enter thread0"くらいで終了してしまう。で色々原因探ってみたんだけど、考えてみればmain関数==メインスレッドなわけで、他のスレッドの生成が終わるとそのまま"return 0;"(プロセス終了)へ一直線なわけだ。んで、どうするかってーと、WaiteForSingleObject/WaitForMultipleObjectsを使ってメインスレッド以外の処理が終わるのを待ってやらなきゃならない。なので、正解は"return 0;"の直前に、

  WaitForMultipleObjects(THREAD_NUM, thread_handle, TRUE, INFINITE);

ってのを書き足してやれば意図通りに。こういうのは図を書いて考えるとミスもないんだろうけど、ペイントとか起動するのもアレなんで、妄想したり紙に書いたりすると良いネ。

あと気になったのはCreateThreadで指定してるthread_funcっていうのはthread_func関数のおいてある位置のポインタ、だよな?ってことはthread_func関数スコープで宣言している変数の実際の位置は全スレッドで同一なのか…?と思ったんだけど、上記のテストプログラムでは別の変数として動作しているわけだから、命令をフェッチしてくる番地が同じなだけで、各スレッドの実際の作業場所であるスタックは異なっているので別々の位置に変数が作成される、と解釈してもいいみたいだ。

となるとstatic変数が特別扱いな感じになってきて、使いようによっては便利だったりバグの温床だったりすると思うんだが…、必要になるまで考えるのやめよ(ぉ。