スレッドを待機する
スレッドを待機するために使用できる手順は次のとおりです。
- スレッドの実行が終了するまで待つ。
- タスクが完了するまで待つ。
- 別のスレッドがこのスレッドの終了を待機していないかどうかをチェックする。
スレッドの実行終了を待機する
- ほかのスレッドの WaitFor メソッドを使用します。
- ロジックをコード化します。たとえば,次のコードは,別のスレッドが実行を終了するまで(スレッドリストオブジェクトを埋めるまで)待ってから,そのリストのオブジェクトにアクセスします。
if ListFillingThread.WaitFor then begin with ThreadList1.LockList do begin for I := 0 to Count - 1 do ProcessItem(Items[I]; end; ThreadList1.UnlockList; end;
if( ListFillingThread->WaitFor() ) { TList* list = ThreadList1->LockList(); for( int i = 0; i < list->Count; i++ ) { DoSomething( list->Items[i] ); } ThreadList1->UnlockList(); }
タスクの終了を待機する
- グローバルスコープの TEvent オブジェクトを作成します。
- ほかのスレッドが待機している操作が終了したときに,TEvent.SetEvent を呼び出します。
- シグナルをオフにするには,TEvent.ResetEvent を呼び出します。
次の例では,OnTerminate イベントハンドラが,クリティカルセクション内のグローバルカウンタを使用して,終了したスレッドの数を把握します。Counter が 0 になると,ハンドラは SetEvent メソッドを呼び出して,すべてのプロセスが終了したことを示すシグナルを通知します。
procedure TDataModule.TaskTerminateThread(Sender: TObject); begin ... CounterGuard.Acquire; {カウンタのためのロックを取得する} Dec(Counter); {グローバルのカウンタ変数をデクリメントする} if Counter = 0 then Event1.SetEvent; {最後のスレッドの場合にシグナルを出す} Counter.Release; {カウンタのためのロックを解放する} ... end;
void __fastcall TDataModule::TaskThreadTerminate( TObject *Sender ) { ... CounterGuard->Acquire(); // カウンタをロックする if( --Counter == 0 ) // カウンタをデクリメントする Event1->SetEvent(); // 最後のスレッドの場合にシグナルを出す CounterGuard->Release(); // ロックを解放する }
メインスレッドは,Counter を初期化し,タスクスレッドを起動します。さらに,TEvent::WaitFor メソッドを呼び出して,すべてのタスクが終了したことを示すシグナルを待ちます。WaitFor は,シグナルが設定されるまで一定の時間だけ待機します。そして,下の表に示す値のいずれかを返します。
次のコード例は,メインスレッドがタスクスレッドを起動し,タスクの完了時に再開する方法を示します。
Event1.ResetEvent; {スレッドを起動する前にイベントをクリアする} for i := 1 to Counter do TaskThread.Create(False); {タスクスレッドを作成して起動する} if Event1.WaitFor(20000) <> wrSignaled then raise Exception; {メインスレッドを続行する}
Event1->ResetEvent(); // スレッドを起動する前にイベントをクリアする for( int i = 0; i < Counter; i++ ) { new TaskThread( false ); if( Event1->WaitFor(20000) != wrSignaled ) throw Exception; // メインスレッドの実行を継続する
メモ: 指定した時間が経過した後もイベントハンドラを待ち続ける場合は,WaitFor メソッドの引数の値に INFINITE を渡します。INFINITE 使用する場合には注意が必要です。期待したシグナルが受け取れないと,スレッドがハングアップします。
別のスレッドがスレッドの終了を待機しているかどうかをチェックする
- Execute 手続き内で,Terminated プロパティをチェックし,これに応答することで,Terminate メソッドを実装します。
- 次に例を示します。
procedure TMyThread.Execute; begin while not Terminated do PerformSomeTask; end;
void __fastcall TMyThread::Execute() { while( !Terminated ) DoSomething(); }
TEvent.WaitFor の戻り値:
値 |
意味 |
wrSignaled |
イベントのシグナルが設定された。 |
wrTimeout |
シグナルが設定されずに指定された時間が経過した。 |
wrAbandoned |
タイムアウト期間が経過する前にイベントオブジェクトが破棄された。 |
wrError |
待機中にエラーが発生した。 |