Waiting for Threads

From RAD Studio
Jump to: navigation, search

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

  1. Use the WaitFor method of the other thread.
  2. 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

  1. Create a TEvent object of global scope.
  2. When a thread completes an operation other threads are waiting for, have the thread call TEvent.SetEvent.
  3. 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

  1. In your Execute procedure, implement the Terminate method by checking and responding to the Terminated property.
  2. 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.


See Also