View Issue Details

IDProjectCategoryView StatusLast Update
0034530FPCDocumentationpublic2021-03-25 13:26
Reportercordylus Assigned ToMichael Van Canneyt  
PrioritynormalSeverityminorReproducibilityhave not tried
Status resolvedResolutionfixed 
Product Version3.0.4 
Target Version3.2.0Fixed in Version3.3.1 
Summary0034530: Thread.WaitFor hangs the program if the thread has been freed already
DescriptionIf FreeOnTerminate is enabled, the following pattern may work one time and hang the other, depending on whether the thread has terminated instantly or not:

That might be wrong use, but the hang makes it hard to debug. Should be some error instead. Delphi (I checked 7 and 2000) gives an error.
Steps To ReproduceAn example with random reproducibility is attached, a dozen of clicks may be required to reproduce. Comment out all TMyThread.Execute function body to make it reproduce every time.
TagsNo tags attached.
Fixed in Revision1538
Attached Files



2018-11-08 19:36

reporter (4,247 bytes)


2018-11-08 19:42

reporter   ~0111868

OS: Windows XP

Jonas Maebe

2018-11-08 19:55

manager   ~0111869

It is not possible to give any reliable results in this scenario. The reason is that after the tthread instance has been freed, its memory can be reused and overwritten by other data. You are getting very lucky in Delphi that you get an error in your use case, but I can't imagine that even Delphi can guarantee that this will happen.


2018-11-08 20:11

reporter   ~0111870

Last edited: 2018-11-08 20:15

View 2 revisions

Shouldn't it error when it tries to use freed data? Or maybe it's possible to check whether the identifier that is being used to wait for is invalid?

Jonas Maebe

2018-11-08 20:20

manager   ~0111871

Memory that is freed still belongs to the application, and can be reused for other class instances. There is no way to detect that the memory has been freed from within the class instance.

Please ask further questions on the mailing list ( or forum (,62.0.html)


2018-11-08 20:57

reporter   ~0111874

I'm pretty sure that the hang is caused by the not implemented properly error handling in TThread.WaitFor. There is an explicit infinite loop that expects certain successful behavior of MsgWaitForMultipleObjects. If only it'd check for error return values instead of trying again indefinitely, that might fix the problem. Please, take a closer look at the problem. If you decide not to fix it, so be it, I won't reopen again.


2018-11-08 21:30

reporter   ~0111875

I have had a similiar issue which is maybe related to this one:

thread1 := TThread.ExecuteInThread(@Proc, nil);
// some more threads executing same Proc function
Writeln('Main procedure done');
// some more WaitFor, one for each thread

Sometimes it didn't showed End msg and I needed to stop my app with control+c


2018-11-08 22:36

reporter   ~0111876

The equivalent Delphi code checks for WAIT_FAILED result and raises an exception with GetLastError data in this case.

Sven Barth

2018-12-25 19:49

manager   ~0112874

This *can not* be reliably solved, because the instance of the thread no longer exists if FreeOnTerminate is set and the thread has terminated.
That it works in Delphi is *pure chance* and the following code shows a deadlock on my system with Delphi:

=== code begin ===

  TTestThread = class(TThread)
    procedure Execute; override;

procedure TTestThread.Execute;


  thd, thd2: TTestThread;
  thd := TTestThread.Create(True);
  thd.FreeOnTerminate := True;
  thd2 := TTestThread.Create(True);
  Writeln(IntToHex(NativeInt(thd), SizeOf(NativeInt) * 2));
  Writeln(IntToHex(NativeInt(thd2), SizeOf(NativeInt) * 2));
    on e: Exception do
      Writeln('Exception: ', e.Message);

=== code end ===

The instance of TTestThread assigned to thd2 will be done in the same memory location as thd and as the thread is suspended thd.WaitFor will wait for the new thread instance thus resulting in a deadlock.

(@Michael: maybe we should add that to TThread's documentation?)

Michael Van Canneyt

2019-01-19 15:58

administrator   ~0113484


Júlio César De Brito Gardona

2021-03-25 05:56

reporter   ~0129870

This code gets the same behavior that this issue :
WIn10 64 pro
fpc 3.20

program fileprocessinglpi;

{$mode objfpc}{$H+}

uses {$IFDEF UNIX} {$IFDEF UseCThreads}
  cthreads, {$ENDIF} {$ENDIF}
  syncobjs { you can add units after this };

  TProcess = class
    D: Integer;
    T1, T2: TThread;

    procedure DoneThread(Sender: TObject);
    procedure DoThread;
    procedure Run;
    constructor Create;
    destructor Destroy; override;

  procedure TProcess.DoneThread(Sender: TObject);

    WriteLn('Thread ', TThread(Sender).ThreadID, ' done. D is currently: ', D);


  procedure TProcess.DoThread;
    I: Integer;
    for I := 1 to 10 do
      //Sleep(10 * Random(30));
      WriteLn('Thread ', TThread.CurrentThread.ThreadID, ' ping ', I);

      //Inc(D, I);


  procedure TProcess.Run;
    T1 := TThread.ExecuteInThread(@DoThread, nil);
    T2 := TThread.ExecuteInThread(@DoThread, nil);
    WriteLn('Main thread done');


  constructor TProcess.Create;

  destructor TProcess.Destroy;
    // FreeAndNil(T1);
    inherited Destroy;


  Process: TProcess;
  Process := TProcess.Create;



Sven Barth

2021-03-25 08:36

manager   ~0129873

Please don't reply to a resolved issue from two years ago. Instead open a new one and reference this one if necessary.

That said: either ExecuteInThread should not set FreeOnTerminate to True or the documentation should not provide the usage of WaitFor as an example. As a workaround you can use TThread.CurrentThread.FreeOnTerminate := False inside your DoThread method and then you also need to free the threads yourself.

Issue History

Date Modified Username Field Change
2018-11-08 19:36 cordylus New Issue
2018-11-08 19:36 cordylus File Added:
2018-11-08 19:42 cordylus Note Added: 0111868
2018-11-08 19:55 Jonas Maebe Note Added: 0111869
2018-11-08 19:55 Jonas Maebe Status new => resolved
2018-11-08 19:55 Jonas Maebe Resolution open => not fixable
2018-11-08 19:55 Jonas Maebe Assigned To => Jonas Maebe
2018-11-08 20:11 cordylus Note Added: 0111870
2018-11-08 20:11 cordylus Status resolved => feedback
2018-11-08 20:11 cordylus Resolution not fixable => reopened
2018-11-08 20:15 cordylus Note Edited: 0111870 View Revisions
2018-11-08 20:20 Jonas Maebe Note Added: 0111871
2018-11-08 20:20 Jonas Maebe Status feedback => resolved
2018-11-08 20:20 Jonas Maebe Resolution reopened => not fixable
2018-11-08 20:57 cordylus Note Added: 0111874
2018-11-08 20:57 cordylus Status resolved => feedback
2018-11-08 20:57 cordylus Resolution not fixable => reopened
2018-11-08 21:00 Jonas Maebe Assigned To Jonas Maebe =>
2018-11-08 21:00 Jonas Maebe Status feedback => new
2018-11-08 21:30 rd0x Note Added: 0111875
2018-11-08 22:36 cordylus Note Added: 0111876
2018-12-25 19:49 Sven Barth Note Added: 0112874
2018-12-25 19:50 Sven Barth Assigned To => Michael Van Canneyt
2018-12-25 19:50 Sven Barth Status new => assigned
2018-12-25 19:50 Sven Barth Category RTL => Documentation
2019-01-19 15:58 Michael Van Canneyt Fixed in Revision => 1538
2019-01-19 15:58 Michael Van Canneyt Note Added: 0113484
2019-01-19 15:58 Michael Van Canneyt Status assigned => resolved
2019-01-19 15:58 Michael Van Canneyt Fixed in Version => 3.3.1
2019-01-19 15:58 Michael Van Canneyt Resolution reopened => fixed
2019-01-19 15:58 Michael Van Canneyt Target Version => 3.2.0
2021-03-25 05:56 Júlio César De Brito Gardona Note Added: 0129870
2021-03-25 08:36 Sven Barth Note Added: 0129873