Skip to content

RTL: Incorrect TThread.Queue/ForceQueue implementation

According to Delphi documentation, when calling TThread.Queue with nil parameter instead of thread, the synchronization object should not know anything about the called thread and RemoveQueuedEvents function that clears the queue at thread termination will leave all Queue/ForceQueue calls in the queue until they are called from Idle.

Proof: https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.Classes.TThread.Queue

However, this was not taken into account in the initial implementation and on the contrary the ThreadID field was added with the comment: "new field ThreadID so that entries with Thread = Nil can be removed": d5cc59c2
When editing the code later, this error was also not noticed: 192bbc07

This behavior is also not described in the FPC documentation: https://docs.freepascal.org/docs-html/rtl/classes/tthread.queue.html

Also, the original edit was made with the note “This is Delphi compatible”, but as you can see from the documentation of Delphi itself, it interprets the first parameter in a completely different way.

As a result of this error, the following code will not work:

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  I := 0;
  TThread.CreateAnonymousThread(
    procedure
    begin
      Inc(I);
      TThread.Queue(nil, procedure
      begin
        // we'll never get here!!!
        Inc(I);
        ShowMessage(IntToStr(I));
      end);
    end).Start;
end;

This behavior has been in Delphi itself since version 2009, where the TThread.Queue() call first appeared, and has never changed again.

To restore compatibility with Delphi code, I suggest applying the following patch: 8.fpc_queue.patch

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information