Root > Advanced topics > Multi-threaded applications > Enabling EurekaLog for background threads > Manual / code

Manual / code

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.

 

A most simple way to enable EurekaLog in thread manually is to use BeginThreadEx/TThreadEx:

Use BeginThreadEx function instead of BeginThread function: created thread will be EurekaLog-enabled (by default).
Use TThreadEx class instead of TThread class: created thread will be EurekaLog-enabled (by default).

 

Both routines are from EBase unit.

 

Important note: never use CreateThread function. Use BeginThread/BeginThreadEx function instead.

 

See the above links for more details about this recommended approach.

 


 

If you can not use BeginThreadEx/TThreadEx in your code (e.g. you do not create threads - think of thread pools as example), then you have to manually enable EurekaLog for your threads, for example:

 

function ThreadFunc(Parameter: Pointer): Integer;
begin
  try

    // Both routines are from EBase unit - 

    // thus both can be used in the application without EurekaLog 

 

    // 1. Name thread for easy identification in debugger and bug reports
    NameThread('This is my thread with Parameter = ' + 
      IntToHex(NativeUInt(Parameter), SizeOf(Pointer) * 2));

 
    // 2. Enable EurekaLog for this thread.
    SetEurekaLogStateInThread(0, True); 
 

    // ... your normal code for the thread ...

 
    Result := 0; 
  except
    ApplicationHandleException(nil); 
    Result := 1; 
  end;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  TID: Cardinal;
begin
  CloseHandle(BeginThread(nil, 0, ThreadFunc, nil, 0, TID));
end;

 

Notice first actions in the thread: setting thread name (description) and enabling EurekaLog for this thread. This template is a recommended code template. Each of your EurekaLog-enabled threads should start with these two actions. Here is the same example for TThread class:

 

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

  // Service calls first:

  NameThread('This is my thread ' + ClassName);

  SetEurekaLogStateInThread(0, True); 
 
  // ... your normal thread code ...
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  Thread: TMyThread;
  E: TObject;
begin
  Thread := TMyThread.Create(False);
  try

    // ...

 

    // Wait for the thread to complete 

    Thread.WaitFor;

 
    // Clear the FatalException property,

    // so it won't be deleted when thread is deleted
    E := Thread.FatalException;

    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;
end;

 

...and for anonymous threads:

 

type
  TForm1 = class(TForm)
  private
    procedure HandleThreadException(Sender: TObject);

  // ...
  end;

 
procedure TForm1.Button1Click(Sender: TObject);
var
  Thread: TThread;
begin
  Thread := TThread.CreateAnonymousThread(
    procedure 
    begin 
      // Service calls first:
      NameThread('This is my anonymous thread');
      SetEurekaLogStateInThread(0, True); 
 
      // ... your normal thread code ...
    end);
  Thread.OnTerminate := Self.HandleThreadException;
  Thread.Start;
  Thread := nil;
end;

 

procedure TForm1.HandleThreadException(Sender: TObject);
var
  Thread: TThread;
begin
  Thread := (Sender as TThread);
  if Assigned(Thread.FatalException) then
    HandleException(Thread.FatalException, False, atThread);
end;

 

...and a very similar code may be applied to any multi-threading framework that you may use: just insert calls to NameThread + SetEurekaLogStateInThread before your actual thread code.

 

Since a single thread may serve multiple tasks in a thread pool - it is recommended to clean after yourself:

 

function MyTask(lpThreadParameter: Pointer): Integer; stdcall;
begin
  // Mark thread for yourself
  NameThread('This is thread pool thread with my task');
  SetEurekaLogStateInThread(0, True); 
 
  try
    // ... your task code ...
    Result := 0; // <- to indicate success
  except
    on E: Exception do
      Result := HandleException(E);
  end;
 
  // Clean after yourself
  // (i.e. mark/prepare thread for other tasks)
  NameThread('');
  SetEurekaLogStateInThread(0, False); 
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  IsMultiThreaded := True;

  Win32Check(QueueUserWorkItem(MyTask, nil, 0));
end;

 

This sample code enables EurekaLog (and sets thread name) only for the duration of our task. When our task is completed, thread will be released into thread pool - so we disable EurekaLog (because we don't know which task will use this thread in the next time).

 

 

See also:




Send feedback... Build date: 2023-09-11
Last edited: 2023-07-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_enable_manual.php