在线程之间同步/发送数据

Wiz*_*ard 12 delphi multithreading synchronization delphi-xe

该应用程序是用Delphi XE编写的.

我有两个类,TBoss和TWorker,它们都是基于TThread.TBoss是一个单实例线程,启动后会创建大约20个TWorker线程.

当boss创建一个TWorker实例时,它会为它分配一个调用同步的方法,当Worker完成它正在做的事情时,它会调用这个方法,允许Boss访问Worker上的记录.

但是我觉得这是一个问题,调用synchronize似乎是锁定整个应用程序 - 阻塞主(ui)线程.真的应该只是将该工作者与老板线程同步....

以前我使用消息/打包记录在线程之间发送内容很好.然而,这样做是更清洁和更好....只是非常阻止.

有没有办法在worker中调用Syncronize只等待Boss线程?

我的代码:

    type 
      TWorker = class(TThread) 
      private 
        fResult : TResultRecord;
        procedure SetOnSendResult(const Value: TNotifyEvent);
        ....
        ....
      public
        property OnSendResult: TNotifyEvent write SetOnSendResult; 
        property Result : TResultRecord read fResult;
        ....
     end;

    ...
    ...
    procedure TWorker.SendBossResults; 
    begin 
      if (Terminated = False) then 
      begin 
        Synchronize(SendResult); 
      end; 
    end; 

    procedure TWorker.SendResult; 
    begin 
      if (Terminated = false) and Assigned(FOnSendResult) then 
      begin 
        FOnSendResult(Self); 
      end; 
    end;
Run Code Online (Sandbox Code Playgroud)

然后在我的Boss线程中,我会做这样的事情

    var 
      Worker  : TWorker; 
    begin 
      Worker              := TWorker.Create; 
      Worker.OnTerminate  := OnWorkerThreadTerminate; 
      Worker.OnSendResult := ProcessWorkerResults;
Run Code Online (Sandbox Code Playgroud)

所以我的老板然后有一个名为ProcessWorkerResults的方法 - 这就是在Synchronize(SendResult)上运行的方法; 工人

    procedure TBoss.ProcessWorkerResults(Sender: TObject); 
    begin 
      if terminated = false then 
      begin 
        If TWorker(Sender).Result.HasRecord then
        begin
          fResults.Add(TWorker(Sender).Result.Items);
        end;
      end; 
    end;
Run Code Online (Sandbox Code Playgroud)

Ken*_*ite 10

Synchronize专门设计用于在线程中执行代码; 这就是为什么它似乎锁定一切.

您可以使用多种方式从工作线程到老板线程进行通信:

  • 向每个工作线程添加一个回调,并在创建时从boss线程中分配它.它可以传回任何参数,以及线程ID或其他标识符.

  • 使用PostThreadMessage将工作线程中的消息发布到boss线程 .这里的缺点是boss线程必须有一个窗口句柄(请参阅Delphi帮助中的Classes.AllocateHWnd和David Heffernan在下面的评论).

  • 使用高质量的第三方线程库.请参阅 OmniThreadLibrary - 它是免费的,操作系统,写得非常好.

我的选择将是第三个.Primoz为您完成了所有艰苦的工作.:)

在你的评论之后,这是我的第一个建议.请注意,这是未经测试的,因为编写TBoss和TWorker线程的代码+测试应用程序对于我这一刻的时间来说有点长......我希望它足以给你一个要点.

type 
  TWorker = class(TThread) 
  private 
    fResult : TResultRecord;
    fListIndex: Integer;
    procedure SetOnSendResult(const Value: TNotifyEvent);
    ....
    ....
  public
    property OnSendResult: TNotifyEvent write SetOnSendResult; 
    property Result : TResultRecord read fResult;
    property ListIndex: Integer read FListIndex write FListIndex;
    ....
  end;

type 
  TBoss=class(TThread)
  private
    FWorkerList: TThreadList; // Create in TBoss.Create, free in TBoss.Free
    ...
  end;

procedure TWorker.SendBossResults; 
begin 
  if not Terminated then
    SendResult; 
end;

procedure TBoss.ProcessWorkerResults(Sender: TObject); 
var
  i: Integer;
begin 
  if not terminated then 
  begin 
    If TWorker(Sender).Result.HasRecord then
    begin
      FWorkerList.LockList;
      try
        i := TWorker(Sender).ListIndex;
        // Update the appropriate record in the WorkerList
        TResultRecord(FWorkerList[i]).Whatever...
      finally
        FWorkerList.UnlockList;
      end;
    end;
  end; 
end;
Run Code Online (Sandbox Code Playgroud)

  • 请更正你的答案 - 线程确实**不要**需要一个窗口句柄才能接收Windows消息.您链接到的API文档尽可能多地说,消息被发布到由id标识的线程,而不是窗口句柄,并且线程需要消息队列并且必须处理排队的消息,但就是这样. (3认同)

Dan*_*eti 8

您可以使用线程安全队列.在DelphiXE中有TThreadedQueue.如果您没有DXE,请尝试OmniThreadLibray - 这个库非常适合所有线程问题.