Показать сообщение отдельно
  #2  
Старый 12.12.2018, 20:38
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,004
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Да вариантов масса.
Кстати, отправлять через сообщения можно все-что угодно, в т.ч. целые структуры. Там только один момент. Если надо отправлять после полной сметри потока (т.е. перед ней, затем поток умирает, а когда произойдет обработка переданной инфы - фиг знает), то надо выделять память для этого в куче (ну и желательно блокировть ее).

Теперь по синхронизации.
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.
Ответить с цитированием