Waiting for Threads
Go Up to How To Build Multithreaded Applications
The following are procedures that can be used to wait for threads.
- Wait for a thread to finish executing.
- Wait for a task to complete.
- Check if another thread is waiting for your thread to terminate.
To wait for a thread to finish executing
- Use the WaitFor method of the other thread.
- Code your logic. For example, the following code waits for another thread to fill a thread list object before accessing the objects in the list:
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(); }
To wait for a task to complete
- Create a TEvent object of global scope.
- When a thread completes an operation other threads are waiting for, have the thread call TEvent.SetEvent.
- To turn off the signal, call TEvent.ResetEvent.
The following example is an OnTerminate event handler that uses a global counter in a critical section to keep track of the number of terminating threads. When Counter reaches 0, the handler calls the SetEvent method to signal that all processes have terminated:
procedure TDataModule.TaskTerminateThread(Sender: TObject); begin ... CounterGuard.Acquire; {obtain a lock on the counter} Dec(Counter); {decrement the global counter variable} if Counter = 0 then Event1.SetEvent; {signal if this is the last thread} Counter.Release; {release the lock on the counter} ... end;
void __fastcall TDataModule::TaskThreadTerminate( TObject *Sender ) { ... CounterGuard->Acquire(); // lock the counter if( --Counter == 0 ) // decrement counter Event1->SetEvent(); // signal if this is the last thread CounterGuard->Release(); // release lock }
The main thread initializes Counter, launches the task threads, and waits for the signal that they are all done by calling the TEvent::WaitFor method. WaitFor waits a specified time period for the signal to be set and returns one of the values in the table below.
The following code example shows how the main thread launches the task threads and resumes when they have completed:
Event1.ResetEvent; {clear the event before launching the threads} for i := 1 to Counter do TaskThread.Create(False); {create and launch the task threads} if Event1.WaitFor(20000) <> wrSignaled then raise Exception; {continue with main thread}
Event1->ResetEvent(); // clear the event before launching threads for( int i = 0; i < Counter; i++ ) { new TaskThread( false ); if( Event1->WaitFor(20000) != wrSignaled ) throw Exception; // now continue with the main thread
Note: If you do not want to stop waiting for an event handler after a specified time period, pass the WaitFor method a parameter value of INFINITE. Be careful when using INFINITE, because your thread will hang if the anticipated signal is never received.
To check if another thread is waiting on your thread to terminate
- In your Execute procedure, implement the Terminate method by checking and responding to the Terminated property.
- This is one way to code the logic:
procedure TMyThread.Execute; begin while not Terminated do PerformSomeTask; end;
void __fastcall TMyThread::Execute() { while( !Terminated ) DoSomething(); }
WaitFor return values
Value |
Meaning |
wrSignaled |
The signal of the event was set. |
wrTimeout |
The specified time elapsed without the signal being set. |
wrAbandoned |
The event object was destroyed before the timeout period elapsed. |
wrError |
An error occurred while waiting. |