两个不同的TThread后代如何共享一个OnTerminate处理程序?

时间:2011-02-02 13:49:31

标签: multithreading delphi

我有一个应用程序启动一些线程来做事情。我为每个访问某些线程变量的线程都有一个TThreadOnTerminate过程,用于使用结果填充网格。 (每个线程执行不同的任务但答案总是相同的,即成功或失败并带有StringList个消息。)

所以我有:

procedure TFormMain.Thread1OnTerminate(Sender: TObject);
begin
  Result := TThread1(Sender).Result;
  AddMessagesToGrid(TThread1(Sender).Messages);
end;

procedure TFormMain.Thread2OnTerminate(Sender: TObject);
begin
  Result := TThread2(Sender).Result;
  AddMessagesToGrid(TThread2(Sender).Messages);
end;

我的问题如下。我可以使用'common'OnTerminate过程来处理我所有线程的结果,如下所示吗?

procedure TFormMain.Thread1OnTerminate(Sender: TObject);
begin
  Result := <Sender Thread>.Result;
  AddMessagesToGrid(<Sender Thread>.Messages);
end;

我们目前正在使用Delphi 2007.很快就会升级(我希望)到Delphi XE。

4 个答案:

答案 0 :(得分:9)

是的,如果所有线程都实现相同的接口,则无法返回结果值和消息。

最简单的方法是使用结果和消息创建一个基本线程类,并使所有当前线程成为该基类的后代。

type
  TBaseThread = class(TThread)
  protected
    function GetResult: Integer; {virtual if you want to}
    function GetMessages: TStrings; {virtual if you want to}
  public
    property Result: Integer read GetResult;
    property Messages: TStrings read GetMessages;

然后按如下方式使用它:

procedure TFormMain.Thread1OnTerminate(Sender: TObject);
begin
  Assert(Sender is TBaseThread);
  Result := TBaseThread(Sender).Result;
  AddMessagesToGrid(TBaseThread(Sender).Messages);
end;

答案 1 :(得分:1)

不确定。向TThread添加一个新的整数字段,为其指定一个数值,然后在OnTerminate中使用该字段:

type
  TYourThread=class(Thread)
  private
    FTag: Integer;
  public
    // Usual constructor, etc.
  published
    property Tag: Integer read FTag write FTag;
  end;

在创建线程的代码中,设置标记值:

MyThread := TYourThread.Create(True);
MyThread.Tag := 1;
MyThread.OnTerminate := ThreadTerminate;
MyThread.Resume;

更新:最新版本的Delphi允许命名线程,并使用MyThread.Start而不是MyThread.Resume。)

在OnTerminate事件处理人员:

procedure TFormMain.ThreadTerminate(Sender: TObject);
var
  TheThread: TMyThread;
begin
  TheThread := TMyThread(Sender);
  AddMessagesToGrid(TheThread);
end;

AddMessagesToGrid方法(或线程的OnTerminate)中,你可以告诉你有哪个线程:

procedure TFormMain.AddMessagesToGrid(const Thread: TMyThread);
begin
  WhatEverGrid.Cells[0, Thread.Tag] := Format('Thread %d', [Thread.Tag]);
  // Do whatever with the Thread message stringlist.
end;

(顺便说一下,您的示例OnTerminate将无法正常工作,因为某个程序没有Result。我怀疑您要设置不同的Result或其他内容。 ..)

答案 2 :(得分:0)

创建线程时,将Thread的OnTerminate方法设置为主窗体中的过程,然后使用Sender对象将其转换为更正类并从中获取正确的属性,像这样:

procedure TFormMain.ThreadOnTerminate(Sender: TObject);
begin
  Result := (Sender as TMyBaseThreadClass).Result;
  AddMessagesToGrid((Sender as TMyBaseThreadClass).Messages);
end;

答案 3 :(得分:0)

您可以调整代码以使用InterlockedIncrement和InterlockedDecrement方法来了解有多少线程。当计数器显示不再有线程时,您可以处理数据。

另外,我看到你为每个线程编写了一个函数。您可以创建自定义方法并将其分配给每个线程

 procedure OnTerminateThrd(Sender: TObject);  

//in the create section for your thread
   yournewthread.OnTerminate := OnTerminateThrd;

以这种方式,所有线程在引发OnTerminate事件时都使用相同的例程。

最好的问候,
拉杜