Root > Advanced topics > Multi-threaded applications > Creating threads > TThreadEx class

TThreadEx class

Previous pageReturn to chapter overviewNext page   

EurekaLog provides two helper routines to simplify thread management: BeginThreadEx function and TThreadEx class - which should be used instead of BeginThread function and TThread class respectively. Both routines are from EBase unit. EBase unit is a special unit that can be included in any application without including full EurekaLog code. Therefore you can safely use EBase unit in your applications even without EurekaLog enabled.

 

Both BeginThreadEx function and TThreadEx class offers two additional arguments:

Thread name;
EurekaLog's state.

 

Note: the EurekaLog's state will be ignored if you compile your application without EurekaLog (or with disabled EurekaLog). On the other hand, the thread name is never ignored.

 

Thread name is arbitrary text string which can contain any combination of characters. Thread name will be shown in debugger (Threads window) and it will be used as thread caption in bug reports. You can use thread name to identificate threads.

 

TThreadEx class is descendant from TThread class - thus, all 5 exception handling methods for TThread class is also applicable to TThreadEx class. For example:

 

type
  TMyThread = class(TThreadEx)
  protected
    procedure Execute; override;
  end;
 
procedure TMyThread.Execute;
begin

  // ... your code ...
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  Thread: TMyThread;
  E: TObject;
begin
  // Create thread
  Thread := TMyThread.Create('Thread Name');
  try

 
    // Wait for thread's completion. 
    // This wait can be implemented in any other way.

    // E.g. you can assign OnTerminate handler;

    // or you can PostMessage from thread to main thread.
    Thread.WaitFor;
 
    // Analyze thread completion.
    // Re-raise any thread error in current thread.

    // You should do this only after the thread has finished.
    E := Thread.FatalException;
    if Assigned(E) then
    begin

      // clear FatalException property
      PPointer(@Thread.FatalException)^ := nil
      raise E;
    end;
 
  finally
    FreeAndNil(Thread);
  end;
end;

 

This code sample works exactly as the previous code sample. You can pass thread name right into TThreadEx's constructor. Thread will be automatically named - regardless of EurekaLog's state.

 

Threads launched with TThreadEx class will be EurekaLog-enabled by default. You can supply optional Boolean argument for TThreadEx's constructor to disable EurekaLog in thread, for example:

 

 Thread := TMyThread.Create('Thread Name', False { disable EurekaLog in thread } );

 

Of course, you can use the same approach while supplying Suspended argument, for example:

 

 Thread := TMyThread.Create(

   False { create thread running },

   'Thread Name',

   False { disable EurekaLog in thread } );

 

 Thread := TMyThread.Create(

   True { create thread suspended},

   'Thread Name',

   True { enable EurekaLog in thread } );

 

TThreadEx class also supports anonymous threads:

 

type
  TForm1 = class(TForm)
    ...
  private
    procedure HandleExceptionInThread(Sender: TObject);
  end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  Thread: TThreadEx;
begin
  Thread := TThreadEx.CreateAnonymousThread(
    procedure 
    begin 
      raise Exception.Create('Test'); 
    end
    'My thread');
  Thread.OnTerminate := Self.HandleExceptionInThread;
  Thread.Start;
  Thread := nil// never access thread var with FreeOnTerminate after Start
  // All anonymous threads are marked with FreeOnTerminate by default
end;
 
procedure TForm1.HandleExceptionInThread(Sender: TObject);
var
  Thread: TThread;
begin
  Thread := (Sender as TThread);
  if Assigned(Thread.FatalException) then
    HandleException(Thread.FatalException);
end;

 

Since creating OnTerminate handler just for handling exceptions in thread is a lot of work - TThreadEx class presents a new property to handle exceptions automatically:

 

type
  TMyThread = class(TThreadEx)
  protected
    procedure Execute; override;
  end;
 
procedure TMyThread.Execute;
begin
  // ... your code ...
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  Thread: TMyThread;
begin
  Thread := TMyThread.Create(True, 'My thread');
  Thread.AutoHandleException := True; // <- added
  Thread.FreeOnTerminate := True;
  Thread.Start;
  Thread := nil// never access thread var with FreeOnTerminate after Start
end;

 

This sample code will automatically invoke HandleException routine for FatalException property of your thread. AutoHandleException property is also available for anonymous threads created with TThreadEx class. See also: how to handle an exception.

 

Notes:

TThreadEx class has the same signature (prototype) for both constructor and Execute method as TThread class. I.e. you don't have to change declarations. The only difference is two additional arguments for the constructor, which are optional. This means that you can just add "Ex" suffix to your existing TThread calls.
The above facts mean that TThreadEx class is source-compatible with TThread class. Therefore, you can do a search&replace "TThread" -> "TThreadEx" over all source files for your project.
If AutoHandleException property is enabled:
oTThreadEx does not clear FatalException property. Thus, this property still may be used to analyze "success/failure" exit status of the thread.
oThread will return non zero exit code when there was exception in this thread. Otherwise (i.e. if there was no exception in the thread) - the exit code will match result of the thread function (usually - zero). This can be used to get "success/failure" exit status of the thread.
If AutoHandleException property is not enabled (default) - thread behavior will be the same as for TThread class:
oFatalException property will store exception in thread.
oThread exit code will be equal to ReturnValue property.

 

 

See also:




Send feedback... Build date: 2018-11-26
Last edited: 2018-11-12
PRIVACY STATEMENT
The documentation team uses the feedback submitted to improve the EurekaLog documentation. We do not use your e-mail address for any other purpose. We will remove your e-mail address from our system after the issue you are reporting has been resolved. While we are working to resolve this issue, we may send you an e-mail message to request more information about your feedback. After the issues have been addressed, we may send you an email message to let you know that your feedback has been addressed.


Permanent link to this article: https://www.eurekalog.com/help/eurekalog/multithreading_tthreadex.php