
Die Kurzform wäre: gibt es inzwischen eine Möglichkeit, einen Datenstruktur (hier: ein String) als Paramter von Synchronize von einem Thread in einen anderen Thread zu übergeben?
Ich hatte das letzte halbe Jahr mit c# zu tun, da gibt es neuerdings drei coole Sprachelemente (Anonyme Funktionen und die Möglichkeit, Variablen zu "capturen" plus Synchronize) die das Problem für mich sehr elegant lösbar machten, in etwa so:
Code: Alles auswählen
Synchronize(() => {Form1.Memo1.add("Bla")});
Mein alter Code, der gleich folgt, kann das nicht direkt, er funktioniert, aber ich finde, er ist im Vergleich recht umständlich.
Frage: alte Postings dass sowas mit FPC (noch?) nicht geht, und in Delphi aber schon (weil es dort anonyme Funktionen gibt) fand ich einige ... geht sowas inzwischen auch mit FPC?
Genug der Vorrede, hier mein (funktionierendes) Codebeispiel. Was mir nicht passt, ist natürlich der Umweg, die auszugebenden Daten erst mal in eine Threadvariable zu speichern, und die Thread-Objekte eng mit dem Memo in Form1 zu koppeln.
Code: Alles auswählen
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, RTTICtrls, ThreadUnit;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
procedure HandleClick(aButton:TButton;var aThread:TTestThread);
public
end;
var
Form1: TForm1;
Thread1,Thread2,Thread3: TTestThread;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
begin
HandleClick(Button1,Thread1);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
HandleClick(Button2,Thread2);
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
HandleClick(Button3,Thread3);
end;
procedure TForm1.HandleClick(aButton: TButton; var aThread: TTestThread);
begin
If not assigned(aThread) then // create thread
begin
aThread := TTestThread.Create(Memo1);
aButton.Caption:=Format('Stop %d',[aThread.ThreadID]);
aThread.Start;
end
else
begin
aThread.Terminate; // terminate thread
while not aThread.isTerminated do // wait for thread to terminate
Application.ProcessMessages;
FreeAndNil(aThread);
aButton.Caption:='Start';
end;
end;
end.
Code: Alles auswählen
unit ThreadUnit;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils, StdCtrls;
type
{ TTestThread }
TTestThread = class(TThread)
private
FisTerminated: boolean;
FMemo: TMemo;
FThreadData: String;
procedure SetMemo(AValue: TMemo);
procedure SetThreadData(AValue: String);
public
property ThreadData:String read FThreadData write SetThreadData;
property isTerminated: boolean read FisTerminated;
procedure ShowData;
Constructor Create(aMemo:TMemo);
Procedure Execute; Override;
end;
implementation
{ TTestThread }
procedure TTestThread.SetThreadData(AValue: String);
begin
if FThreadData=AValue then Exit;
FThreadData:=AValue;
end;
procedure TTestThread.SetMemo(AValue: TMemo);
begin
if FMemo=AValue then Exit;
FMemo:=AValue;
end;
procedure TTestThread.ShowData;
begin
FMemo.Lines.add(Format('Thread %d says: %s',[Self.ThreadID,FThreadData]));
end;
constructor TTestThread.Create(aMemo: TMemo);
begin
inherited create(true);
self.FreeOnTerminate := false;
FMemo := aMemo;
end;
procedure TTestThread.Execute;
var
SleepTime:LongInt;
begin
FisTerminated := false;
FThreadData := 'Thread started';
Synchronize(@ShowData);
while not terminated do
begin
SleepTime := Random(4900) + 100;
FThreadData := Format('I am alive! Going to sleep for %d ms',[SleepTime]);
Synchronize(@ShowData);
Self.Sleep(SleepTime);
end;
FThreadData := 'Thread stopped';
Synchronize(@ShowData);
FisTerminated := true;
end;
end.