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

...handle an exception in a thread?

Previous pageReturn to chapter overviewNext page   

Important: as a general rule, you should write your application in a such way that it will behave correctly without EurekaLog on board. This means that if your or 3rd party code throws an exception in a thread - it must be handled in a way that you expect. For example, by showing an error message, canceling action, retrying, etc. Once your application behaves like it is supposed to do - then you add EurekaLog for it. EurekaLog will auto-handle all unhandled exceptions automatically (by hooking few well-known places), and for everything else - you can call EurekaLog from your own handlers when needed. In other words:

Incorrect: your application does not show messages for exceptions in thread and you are adding EurekaLog in hopes to fix this behavior;
Correct: your application correctly handles thread exceptions and you are adding EurekaLog to receive reports about such exceptions.

 

 

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 a more complete guide - see our multithreading in EurekaLog series.

 

BeginThread

If you are using BeginThread function:

 

uses
  EBase; // for BeginThreadEx
 
// IMPORTANT: 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

  // Notify EurekaLog that this thread has started

  _NotifyThreadStart;

 
  // 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
  // IMPORTANT: TThread was replaced with TThreadEx
  TMyThread = class(TThreadEx
  protected
    procedure Execute; override;
  end;
 
  Thread := TMyThread.Create(False); // Thread: TMyThread;
  try

    // ...
 
    Thread.WaitFor;
    E := Thread.FatalException; // E: Exception;

 

    // Clear the FatalException property,

    // so it won't be deleted when thread is deleted
    PPointer(@Thread.FatalException)^ := nil

 

    // Re-raise thread's exception 

    if Assigned(E) then

      raise E;

 

    // What if there is no exception, but thread failed?

    if Thread.ReturnValue <> 0 then

      Abort;

 

    // Success

    // Do something with thread here...

    // ...

 

  finally
    FreeAndNil(Thread);
  end;

 

Note: this is only one of many possible methods.

 

If you are using TThread class and do not wait for the thread (in other words: "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 HandleThreadException(Sender: TObject);
  end;
 
procedure TMyThread.HandleThreadException(Sender: TObject);
begin
  if Assigned(FatalException) then
    HandleException(FatalException, False, atThread);
end;
 
  Thread := TMyThread.Create(True); // Thread: TMyThread;
  Thread.FreeOnTerminate := True;
  Thread.OnTerminate := Thread.HandleThreadException;
  Thread.Start;

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

 

Alternatively, if you do not want or can not use TThreadEx - 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: 2024-09-30
Last edited: 2024-07-08
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