Ich musste deinen Text mehrmals lesen - und habe ihn dann mal nach Pascal übersetzt.mschnell hat geschrieben: Di 11. Mai 2021, 13:28 Achtung; Da beliebig viele Events/Mitteilungen in der Queue warten können,. muss man die an den Mainthread zu übertragenden Daten ebenfalls Queuen. Ein hübscher Trick ist dafür eine Transport Klasse zu definieren, jeweils ein Daten-Transport Element zu instanzeren und diese Instanz als Parameter per "Queue" zu übergeben und die Insanz-Variable dann zu vergessen. Im Maintread dann die Daten rausholen und free aufrufen um das Transport-Element zu zerstören.
Man nehme ein Formular mit Listbox und Button.
Code: Alles auswählen
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
type
TThreadDataContainer = class(TObject)
public
SyncData: String;
procedure SyncMethod;
end;
TMyThread = class(TThread)
protected
procedure Execute; override;
end;
TForm1 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
procedure Button1Click(Sender: TObject);
private
mythread: TMyThread;
public
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
begin
if Assigned(mythread) then
begin
mythread.Terminate;
mythread.WaitFor;
mythread.Destroy;
mythread := nil;
ListBox1.AddItem('Thread terminated', nil);
end
else
begin
ListBox1.AddItem('Thread started', nil);
mythread := TMyThread.Create(False);
end;
end;
{ TThreadDataContainer }
procedure TThreadDataContainer.SyncMethod;
begin
// Der direkte Zugriff auf Form-Controls von Außen ist keine sauberes Entwurfsmuster
Form1.ListBox1.AddItem(Self.SyncData, nil);
Self.Destroy;
end;
{ TMyThread }
procedure TMyThread.Execute;
var
Container: TThreadDataContainer;
begin
while not Terminated do
begin
Container := TThreadDataContainer.Create;
// Nur als Beispiel geeignet: FormatDateTime ist nur threadsicher, wenn FormatOptions mitgegeben wird.
// Da DefaultFormatSettings aber nicht geändert wird, ist das für eine Demo in Ordnung.
Container.SyncData := FormatDateTime('yyyy-mm-dd hh:nn:ss', now());
Queue(@Container.SyncMethod);
// Objektreferenz vergessen; wird im Mainthread aufgerufen
Container := nil;
Sleep(1000);
end;
end;
end.