ホームに戻る
 13、スレッド

Windows はタスク管理を行うことで複数のプロセスを
同時に動いているかのように見せかける。
1つのアプリケーションは1つのプロセスに相当し、
複数のプロセスが動作している場合は
短期間にプロセスを切り替えることによって、
アプリケーションが同時に動いているように見せかける。
もし1つのプロセスがほとんどアイドル状態であれば処理をすぐに返すので
より動作しているプロセスに多くのCPU資源を割り振れる。

1つのプロセスは最低でも1つのスレッドを持つ。
プロセス内の1つのスレッドは WinMain から始まる。
次のスレッドを作成する場合は最初のスレッドから作成を行う。
スレッド間は特に何もしなければ非同期で動作する。
スレッドの切り替えはプロセスの切り替えよりも早い。

スレッドの作成にはAPIの CreateThread を使うが、
CreateThread はCのスタンダードライブラリと混同できない。
Cのスタンダードライブラリは通常は実行開始時に初期化されるが、
複数のスレッドがこの初期化領域を利用することで食い違いが生じる。
この問題を回避するために _beginthread を用いる。
_beginthread は具体的にはAPIではなくコンパイラのライブラリであり
内部ではスレッドごとのCのスタンダードライブラリの初期化を行い
次に内部でAPIの CreateThread を呼び出している。
_beginthread はコンパイラごとに使い方が異なる可能性が十分にあり、
そもそも _beginthread という名称でない可能性もある。

Borland C++ Compiler では process.h をインクルードし、
コンパイラオプションに -WM をつける。

スレッドの終了を待つには WaitForSingleObject を用いる。
第1引数がスレッドのハンドルで第2引数はタイムアウト時間をミリ秒で指定。
タイムアウト時間は 0 ですぐに処理を返し、INFINITE で無限に待つ。
戻り値は WAIT_TIMEOUT でスレッド動作中、WAIT_OBJECT_0 はスレッド終了、
WAIT_FAILED でエラーをあらわす。
WaitForMultipleObjects では一度に複数のスレッドを待てる。

スレッドの戻り値は GetExitCodeThread で調べることができる。
第1引数がスレッドのハンドルで第2引数は戻り値を格納する変数のポインタ。
APIの戻り値は成功で 0 以外の数値。失敗は 0。
GetExitCodeThread はスレッドが終了していない場合に STILL_ACTIVE を入れるが、
スレッドの戻り値との区別がつかないため、
スレッド終了の判断は WaitForSingleObject を用いるべきである。

unsigned long _beginthread(
  void (*__start)(void *),
  unsigned __stksize,
  void *__arg
);

__start:スレッド関数を指定。
__stksize:スレッドのスタックサイズ。0 でディフォルトサイズを割り当て。
__arg:スレッドに渡す。

成功時にはスレッドハンドルを返し、失敗時は 0 を返す。
スレッドハンドルはスレッド終了時に自動的に閉じるため、
CloseHandle を呼ぶ必要は無い。
_endthread もスレッド終了時に暗黙に呼び出される。

unsigned long _beginthreadex(
  void *__security_attr,
  unsigned __stksize,
  void (__stdcall *__start)(void *),
  void *__arg,
  unsigned __create_flags,
  unsigned *__thread_id
);

__security_attr:セキュリティ属性。何も無ければ NULL。
__stksize:スレッドのスタックサイズ。0 でディフォルトサイズを割り当て。
__start:スレッド関数を指定。
__arg:スレッドに渡す。
__create_flags:スレッドの作成フラグ。通常は 0。
__thread_id:スレッドIDを受け取る変数のポインタ。

成功時にはスレッドハンドルを返し、失敗時は 0 を返す。
_beginthread と違ってこちらは CloseHandle を呼ぶ必要がある。
_endthreadex はスレッド終了時に暗黙に呼び出される。

inserted by FC2 system