Delphi TTask和UI线程同步

时间:2015-03-27 11:18:16

标签: multithreading delphi

我转换了一个串行运行多个环境检查的程序,使用TTask让检查并行运行。每个检查都会在UI中报告其状态。要同步对UI I的访问:

  1. 向检查对象添加了一个通知事件,并将其连接到主窗体上的处理程序。
  2. 将反映支票状态的列表视图项的索引分配给支票本身 - 以便以后可以在UI线程中检索它。
  3. 主表单处理程序使用TThread.Synchronize(...)在主UI线程中运行lambda,该线程执行列表项的实际更新。它传递了检查对象,因此它可以查询其状态。
  4. 它可以正常运行,但是让它回到UI线程感觉好像很多。由于这是我第一次使用TTask,我想我会在这里征求意见。

    提前感谢您的想法。

    以下是代码:

      type
    
      TTest = class;
    
      TTestNoticeEvent = procedure(sender: TTest; token: integer) of object;
    
      TTest = class
      public
        constructor Create(token: integer; runtime: integer);
        destructor Destroy; override;
    
      public
        procedure Test;
    
      protected
        procedure Fire_NoticeEvent;
    
      protected
        FToken: integer;
        FStatus: string;
        FRuntime: integer;
        FTestNoticeEvent: TTestNoticeEvent;
    
      public
        property Token: integer read FToken write FToken;
        property Status: string read FStatus;
        property OnNotice: TTestNoticeEvent read FTestNoticeEvent
          write FTestNoticeEvent;
      end;
    

    Fire_NoticeEvent代码是:

    procedure TTest.Fire_NoticeEvent;
    begin
      if Assigned(FTestNoticeEvent) then
        FTestNoticeEvent(Self, FToken);
    end;
    

    然后从主要形式:

    这是分配给每个TTest实例的OnNotice的表单方法。

    procedure TfrmMain.OnTestNoticeEvent(sender: TTest; token: integer);
    begin
      TThread.Synchronize(
        nil,
        procedure
        begin
          Self.UpdateTests(sender, token);
        end);
    end;
    

    UpdateTests方法的代码是:

    procedure TfrmMain.UpdateTests(sender: TTest; token: integer);
    begin
      lbTests.Items[token] := sender.Status;
    end;
    

1 个答案:

答案 0 :(得分:1)

由于您只想将令牌和字符串传递给主线程,因此这样做会更简单:

Type
  TTestNoticeEvent = procedure(const status: String; token: integer) of object;

procedure TfrmMain.OnTestNoticeEvent(const status: String; token: integer);
begin
  TThread.Synchronize(
    nil,
    procedure
    begin
      lbTests.Items[token] := status;
    end);
   // Or queue this update async to the GUI as David suggests
   {
   TThread.Queue( nil,
    procedure
    begin
      lbTests.Items[token] := status;
    end);
   }
end;

procedure TTest.Fire_NoticeEvent;
begin
  if Assigned(FTestNoticeEvent) then
    FTestNoticeEvent(Status, Token);
end;

现在,UI部分与TTest结构的任何依赖性分离。