Да вариантов масса.
Кстати, отправлять через сообщения можно все-что угодно, в т.ч. целые структуры. Там только один момент. Если надо отправлять после полной сметри потока (т.е. перед ней, затем поток умирает, а когда произойдет обработка переданной инфы - фиг знает), то надо выделять память для этого в куче (ну и желательно блокировть ее).
Теперь по синхронизации.
Synchronize никто не отменял (это для синхронизации с главным тредом). Если у тебя потоков много, то придется еще и синхронизировать их между собой через критические секции.
Вот маленький пример с использованием делегата (это шаблон проектирования такой):
Поток:
Код:
unit Unit2;
interface
uses
System.Classes;
type
TCallMainFormEvent = procedure (AMsg : String) of object;
TWorkerThread = class(TThread)
private
{ Private declarations }
FCallBack : TCallMainFormEvent;
FMsg : String;
FID : Integer;
procedure CallMainForm;
protected
procedure Execute; override;
public
constructor Create(CreateSuspned : Boolean; CallBack : TCallMainFormEvent);
end;
implementation
{
Important: Methods and properties of objects in visual components can only be
used in a method called using Synchronize, for example,
Synchronize(UpdateCaption);
and UpdateCaption could look like,
procedure TWorkerThread.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end;
or
Synchronize(
procedure
begin
Form1.Caption := 'Updated in thread via an anonymous method'
end
)
);
where an anonymous method is passed.
Similarly, the developer can call the Queue method with similar parameters as
above, instead passing another TThread class as the first parameter, putting
the calling thread in a queue with the other thread.
}
{ TWorkerThread }
uses
System.SysUtils, SyncObjs;
var
ThreadSync : TCriticalSection;
constructor TWorkerThread.Create(CreateSuspned : Boolean; CallBack : TCallMainFormEvent);
begin
FCallBack := CallBack;
FMsg := ''; // Just in case
FID := Random(2000000000); // Just generate random ID for each thread
inherited Create(CreateSuspned);
end;
procedure TWorkerThread.Execute;
var
thrdDelay : Integer;
begin
FMsg := 'Thread started.';
Synchronize(CallMainForm);
thrdDelay := Random(5000); // random delay 0 - 5 second
Fmsg := Format('Thread delay set to %d miliseconds.',[thrdDelay]);
Synchronize(CallMainForm);
Sleep(thrdDelay);
FMsg := 'Thread finished.';
Synchronize(CallMainForm);
end;
procedure TWorkerThread.CallMainForm;
begin
ThreadSync.Enter;
Try
If Assigned(FCallBack) Then FCallBack(Format('Thread #%d: %s',[FID,FMsg]));
Finally
ThreadSync.Leave;
End;
end;
initialization
ThreadSync := TCriticalSection.Create;
finalization
ThreadSync.Free;
end.
Гл. форма (на форме кнопка и мемо):
Код:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TMainForm = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
procedure ThreadCallBack(Msg : String);
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
uses Unit2;
procedure TMainForm.Button1Click(Sender: TObject);
const
thrdNmb : Integer = 10; // Number of threads to create
var
I : Integer;
Thrd : TWorkerThread;
begin
Memo1.Lines.Clear;
For I := 1 To thrdNmb Do
Begin
Thrd := TWorkerThread.Create(True,ThreadCallBack);
Thrd.FreeOnTerminate := True;
Thrd.Resume;
End;
end;
procedure TMainForm.ThreadCallBack(Msg : String);
begin
Memo1.Lines.Add(Msg);
end;
end.
Код проверен в D10.2.3 Berlin.