我有一个应用程序启动一些线程来做事情。我为每个访问某些线程变量的线程都有一个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。
答案 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事件时都使用相同的例程。
最好的问候,
拉杜