Root > Advanced topics > Multi-threaded applications > Creating threads > BeginThread Function

BeginThread Function

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.


BeginThread RTL function is basic function to create threads from Delphi / C++ Builder code. This function is a simple wrapper for system CreateThread function.


Important note: it is recommended to use BeginThreadEx function instead of BeginThread function.


Note: when your thread is processing exception, the processing will be performed in a background thread. EurekaLog's event handlers will be called from a background thread. You need to use some sort of synchronization if you are accessing global data in your EurekaLog's event handlers. This also means that several threads can process multiple exceptions simultaneously at the same time. You can avoid this by marshaling processing to main thread. For example, you can use TThread(Ex) and analyze .FatalException property in your main thread. See description of TThreadEx class for examples. Alternatively, you may use "Consecutive processing" option.


BeginThread function has the following differences from CreateThread:

BeginThread will make other RTL calls thread-safe (such as memory/heap operations);
BeginThread will handle any unhandled thread exception by passing it into SysUtils.ShowException routine;
BeginThread uses more Pascal-friendly function prototype. The functionality remains the same: there is a custom argument (pointer) and an integer return value.


There are no other differences between RTL's BeginThread and system's CreateThread functions. Therefore BeginThread is RTL's analog of system function.


Warning: you should never use CreateThread function. Always use BeginThread/BeginThreadEx function instead of CreateThread function.


EurekaLog will install wrapper for any BeginThread's thread function to catch unhandled exceptions in threads (as long as "Use low-level hooks" option is enabled). Therefore you don't need to write any additional code if you're going to always use EurekaLog in your applications. EurekaLog will show a usual EurekaLog error dialog with full bug report and terminate the application.


Important note: EurekaLog has to be enabled for background threads.


Important note: turning off low-level hooks means that EurekaLog will not install additional hooks for API functions. This means that EurekaLog will not intercept important system calls. For example, EurekaLog will not hook ExitThread function, which means EurekaLog will not know when a thread exits. This will lead to thread information stored forever - until application terminates. You can call internal _NotifyThreadGone or _CleanupFinishedThreads functions (from EThreadsManager unit) to notify EurekaLog about thread's termination. Such manual notifications can be avoided by using EurekaLog's wrappers (TThreadEx, for example).


However, if you want to compile your application with and without EurekaLog (for example, as release/debug builds) or if you don't want to install low-level hooks (for better compatibility with external tools) - then you will use a default exception handling provided by BeginThread function. Any exception in threads created with BeginThread function will be handled by RTL by passing exception object to SysUtils.ShowException function. However, the default processing has the following drawbacks:

SysUtils.ShowException function is a low-level function. Error dialog from SysUtils.ShowException is a low-level error dialog (with RAW exception address), it differs from a typical error dialog in application;
Default exception handling terminates application after exception in thread;
Default exception handling works in unexpected way when running outside of the debugger: there will be system error dialog followed by error dialog from SysUtils.ShowException function. There may be some other error dialogs - which are invoked during terminating application from background thread.


Therefore, a default exception handling is usually not good enough for a typical application.


Summary: you should manually catch all exceptions in thread via explicit try/except block. This is also indicated in BeginThread documentation "ThreadFunc should handle all of its own exceptions". For example:


function ThreadFunc(Parameter: Pointer): Integer;

    // 1. Name the thread for easy identification in debugger and bug reports
    NameThread('This is my thread');

    // 2. Activate EurekaLog for this thread.
    SetEurekaLogStateInThread(0, True); 
    // 3. <- ... your code for the thread ...


    Result := 0; // to indicate "success"
    // Handle any exception in thread
    ApplicationHandleException(nil); // from Classes unit
    Result := 1; // to indicate "failure"
procedure TForm1.Button1Click(Sender: TObject);
  TID: Cardinal;
  // This code ignores any failures in thread, but

  // you may want to use GetExitCodeThread function.
  CloseHandle(BeginThread(nil, 0, ThreadFunc, nil, 0, TID));


Note: while most calls to VCL are not thread-safe, ApplicationHandleException function is a default global exception handler. This function is called to handle exceptions by multi-threaded applications. Therefore, this function is thread-safe. Alternative approach is to use HandleException function from EBase unit. HandleException function will show standard error dialog if EurekaLog was not enabled. HandleException function will show EurekaLog error dialog if EurekaLog was enabled. EBase unit is a special unit that can be included in any application without including full EurekaLog code. See also: how to handle an exception.


This code sample will gracefully handles any exception in thread - regardless if EurekaLog is enabled for application or not:

EurekaLog is enabled: this sample will show usual EurekaLog's error dialog with full bug report;
EurekaLog is not enabled: this sample will show error message in message box.


Important note: EurekaLog has to be enabled for background threads.



See also:

Send feedback... Build date: 2022-03-28
Last edited: 2022-02-15
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: