The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 4,262 other subscribers

Application shutdown: wait for all threads to terminate or not?

Posted by jpluimers on 2019/02/21

A while ago, I ran into a problem that an anonymous thread would run longer than the main thread of the application.

This caused all sorts of trouble, so in this case I decided to fix it for that particular thread.

There are various opinions if this should be done for all threads or not. Like always, it depends, so it is good to mention a few:

This particular case resulted into the memory manager shutting down earlier than the anonymous thread, but the anonymous thread was still using memory allocation functions, resulting into a few things of which you do not want the first and second to happen on a continuous integration system:

  1. Error messages during shutdown, which is unwanted on a headless system:
    ---------------------------
    MyIntegrationTests.exe: MM Operation after uninstall.
    ---------------------------
    FastMM has detected a GetMem call after FastMM was uninstalled.
    ---------------------------
    OK 
    ---------------------------

    or

    ---------------------------
    MyIntegrationTests.exe: MM Operation after uninstall.
    ---------------------------
    FastMM has detected a FreeMem call after FastMM was uninstalled.
    ---------------------------
    OK 
    ---------------------------

    either of them followed by

    ---------------------------
    Error
    ---------------------------
    Runtime error 203 at 00408EFF
    ---------------------------
    OK 
    ---------------------------

    or

    ---------------------------
    Error
    ---------------------------
    Runtime error 204 at 0040AFE9
    ---------------------------
    OK 
    ---------------------------

    The errors are mappings of:

    203, { reOutOfMemory }
    204, { reInvalidPtr }
  2. The MyIntegrationTests_MemoryManager_EventLog.txt to rapidly grow to 100s of megabytes.
  3. The MyIntegrationTests_MemoryManager_EventLog.txt not to be truncated.

This particular case was easy to fix by adding a global (but implementation section contained) boolean indicating if the thread was already finished:

unit DebugInformationLoaderUnit;

interface

implementation

uses
  JclDebug;

var
  LoadDebugInformationAsyncFinished: Boolean = False;

procedure LoadDebugInformationAsync;
begin
  TThread.CreateAnonymousThread(
    procedure
    begin
      TThread.NameThreadForDebugging('LoadDebugInforoamtionAsync');
      DebugInfoAvailable(MainInstance);
      LoadDebugInformationAsyncFinished := True;
    end).Start;
end;

initialization
  LoadDebugInformationAsync;

finalization
  while not LoadDebugInformationAsyncFinished do
  begin
    Sleep(1);
  end;
end.

In addition, I did this to suppress message boxes outside Delphi:

program MyIntegrationTests;

...

{$Include FastMM4Options.inc}

uses
  FastMM4 in '..\..\..\Shared\FastMM4.pas',
  System.Classes,
...;

{$R *.RES}

begin
  TThread.NameThreadForDebugging(ParamStr(0));

  SuppressMessageBoxes := SuppressMessageBoxes // follow pattern in FastMM4.FinalizeMemoryManager
    {$ifdef RequireIDEPresenceForLeakReporting}
        and DelphiIsRunning
    {$endif}
    {$ifdef RequireDebuggerPresenceForLeakReporting}
        and ((DebugHook <> 0)
        {$ifdef PatchBCBTerminate}
        or (Assigned(pCppDebugHook) and (pCppDebugHook^ <> 0))
        {$endif PatchBCBTerminate}
        )
    {$endif}
    ;
  {$WARN SYMBOL_PLATFORM OFF} NoErrMsg := {$WARN SYMBOL_PLATFORM ON} SuppressMessageBoxes; // Set RTL message boxes as well;

  ...
end.

–jeroen

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.