Win32並行処理プログラミング入門5
前回のサンプルは、タイムアウトになるのが原因で、メインスレッドが先に終わっていました。このサンプルは単純なので、理由はコードを読めば直ぐに分かります。しかし、タイムアウトになったのか、もしくはスレッドの処理が終わったのか、どちらが原因なのか分かりません。これでは、デバッグ時に困ります。WaitForSingleObject関数が終了した原因を知りたい場合は、関数の戻り値を使用します。これを踏まえて、前回のサンプルを改良したものを掲載しますので見て下さい。
#include <iostream>
#include <windows.h>
#include <tchar.h>
#include <process.h>
using namespace std;
unsigned __stdcall ThreadFunc( void* pvParam )
{
//解説のために処理開始を遅らせる
Sleep( 1000 );
//関数に渡された値をコンソール画面で知らせる
int value = PtrToInt( pvParam );
cout << "スレッドに渡された値は"
<< value << "です。" << endl;
return 0;
}
int _tmain( int, _TCHAR* )
{
//スレッド開始
int paramValue = 1000;
HANDLE hThread = ( HANDLE ) _beginthreadex (
__nullptr,
0U,
ThreadFunc,
( void * ) ( INT_PTR ) paramValue,
0U,
__nullptr );
//タイムアウト時間をミリ単位で指定
//※指定した時間は正確ではありません
DWORD result = WaitForSingleObject( hThread, 10 );
//WaitForSingleObject関数が終了した原因
switch( result ) {
case WAIT_OBJECT_0:
cout << "スレッドの処理が終わりました。" << endl;
break;
case WAIT_TIMEOUT:
cout << "タイムアウトしてしまいました。" << endl;
break;
};
//ハンドルを閉じる
CloseHandle( hThread );
return 0;
}
このサンプルを実行すると、コンソールに「タイムアウトしてしまいました。」と表示されます。この様に、WaitForSingleObject関数の戻り値を調べると、関数が終了した原因が分かります。なお、WaitForSingleObject関数の第2引数に、INFINITEを渡すとスレッドが終了するまで待ちます。それならば、常にINFINITEを渡せばよいと考える人がいるかもしれません。しかしながら、その考えは実務で通用しません。
例えば、まだ不安定なコードをデバッグをしている状況下で、INFINITEを指定してしまうと、永遠に処理が終わりません。他にも、基幹系業務システムのように、複雑な要素が絡み合っている大規模なシステムの場合、不幸な要因が重なって、処理が永遠に終わらないかもしれません。最悪なケースでは、新しく生成したスレッドがWaitForSingleObject関数を実行し、メインとなる処理を行っているスレッドは別に作動しているかもしれません。この状況では、永遠に待機処理が終わらない事すら気付かない可能性があります。
危険な状態の放置を避ける為に、タイムアウト時間は極力指定するべきです。ただし、このサンプルのように、メインとなる処理をしているスレッド(メインスレッド)が待機する場合、INFINITEを指定すると良い状況もあります。ですが、予め危険を避ける為に、実務では珍しい状況だと考えるべきです。続く...