Root > How to... > ...handle an exception? > ...handle exception in thread?

...handle exception in thread?

Previous pageReturn to chapter overviewNext page   

There are many ways to create and use threads in Delphi. Therefore there are many ways of handling thread exceptions. Typical examples are listed below. For more complete guide - see our multithreading in EurekaLog series.

 

BeginThread

If you are using BeginThread function:

 

uses
  EBase; // for BeginThreadEx
 
// BeginThread is replaced with BeginThreadEx
TH := BeginThreadEx(nil, 0, YourThreadFunc, nil, 0, TID); 

 

Alternatively:

 

uses
  EBase; // for SetEurekaLogStateInThread
 
function YourThreadFunc(Parameter: Pointer): Integer;
begin
  // Enable EurekaLog for this thread
  SetEurekaLogStateInThread(0, True);
  
  // Your actual code goes here
end;

 

  // Original BeginThread is used

  TH := BeginThread(nil, 0, YourThreadFunc, nil, 0, TID); 

 

Or (when you disable low-level hooks for better compatibility with exe protectors):

 
uses
  EBase, // for SetEurekaLogStateInThread and HandleException

  EThreadsManager, // for _NotifyThreadGone

  ETypes; // for atThread

  
function YourThreadFunc(Parameter: Pointer): Integer;
begin
  // Enable EurekaLog for this thread
  SetEurekaLogStateInThread(0, True);
 
  try
    // Your actual code goes here
  except
    on E: Exception do
      Result := HandleException(E, False, atThread);
  end;

 

  // Notify EurekaLog that this thread is done

  _NotifyThreadGone;
end;
 

  // Original BeginThread is used
  TH := BeginThread(nil, 0, YourThreadFunc, nil, 0, TID);

 

See for more details:

 

 

TThread

If you are using TThread class and wait for the thread to finish:

 

uses
  EBase; // for TThreadEx
 
type
  // TThread was replaced with TThreadEx
  TMyThread = class(TThreadEx) 
  protected
    procedure Execute; override;
  end;
 
  Thread := TMyThread.Create(False); // Thread: TMyThread;
 
  // ...
 
  Thread.WaitFor;
  E := Thread.FatalException; // E: Exception;

  // Clear FatalException property,

  // so it will not be deleted when thread is deleted
  PPointer(@Thread.FatalException)^ := nil
  FreeAndNil(Thread);
  if Assigned(E) then
    raise E;

 

Note: this is only one of many possible methods.

 

If you are using TThread class and do not wait for the thread (e.g. "fire and forget" with FreeOnTerminate = True):

 

uses
  EBase,  // for TThreadEx
  ETypes; // for atThread
 
type
  TMyThread = class(TThreadEx)
  protected
    procedure Execute; override;
 
    // OnTerminate handler
    // You could move it to Form or any other object
    procedure Cleanup(Sender: TObject);
  end;
 
procedure TMyThread.Cleanup(Sender: TObject);
begin
  if Assigned(FatalException) then
    HandleException(FatalException, False, atThread);
end;
 
  Thread := TMyThread.Create(True); // Thread: TMyThread;
  Thread.FreeOnTerminate := True;
  Thread.OnTerminate := Thread.Cleanup;
  Thread.Start;

  // Do not access FreeOnTerminate thread variable after .Start
  Thread := nil

 

Alternatively, you could modify both examples above as:

 

type
  TMyThread = class(TThread) // - TThread is used

  // ...

 

procedure TMyThread.Execute;

begin
  // Enable EurekaLog for this thread
  SetEurekaLogStateInThread(0, True);
  
  // Your actual code goes here
end;

 

// ... same as above ...

 

See for more details:

 

 

Thread pools

If you are using any kind of thread pool:

 

uses
  EBase,  // for SetEurekaLogStateInThread and HandleException

  ETypes; // for atThread

 

function MyTask(lpThreadParameter: Pointer): Integer; stdcall;
begin
  // Mark thread for yourself
  SetEurekaLogStateInThread(0, True); 
  try
    try
      // ... your task code ...
      Result := 0; // <- to indicate success
    except
      on E: Exception do

        // To handle exception and indicate failure  
        Result := HandleException(E, False, atThread); 
    end;
  finally
    // Clean after yourself
    // (i.e. mark/prepare thread for other tasks)
    SetEurekaLogStateInThread(0, False); 
  end;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  IsMultiThreaded := True;

 

  // Execute MyTask in a background thread
  Win32Check(QueueUserWorkItem(MyTask, nil, 0));
end;

 

See for more details:

 

 

See also:




Send feedback... Build date: 2019-12-02
Last edited: 2019-06-14
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/how_to_handle_thread_exception.php