我有一个使用Delphi 10创建的Delphi(Windows)应用程序,它有一些我想要转换为使用线程的阻塞调用。不幸的是,这些不是程序,而是功能。 (有关如何从线程返回函数结果的信息似乎更加有限。)我正在尝试熟悉OmniThreadLibrary,因为它似乎是Delphi中最灵活和最受支持的线程库,但我有了解如何做到这一点的麻烦。
我已经能够使各种OmniThreadLibrary例程与程序一起使用,但是当我尝试设置一个函数时,我得到一个关于捕获结果的错误。当我使用OmniThreadLibrary的Future示例作为起点时,我可以让函数工作,但我无法弄清楚如何连接到事件监视器,如何从任务发送消息等等。所以,似乎好像无论我试图解决这个问题,我都会忽略一些事情。
目前,我的程序执行以下操作:
If myPing(IPAddress) then
begin
//Do other things here…
end;
因为myPing是阻塞的,我实际上需要它等到myPing返回true才进一步处理之前,应用程序在此过程中变得缓慢。我想将myPing调用放在一个线程中,这将解决缓慢的问题,但我无法弄清楚如何使用OmniThreadLibrary以函数的形式做到这一点。 (除非我使用未来,在这种情况下我无法弄清楚如何连接到事件监视器。)
编辑1:自从我的原帖以来,我取得了一些进展。通过在函数之后添加Parallel.TaskConfig.MonitorWith(Form1.OmniEventMonitor1)到我的代码,我能够将事件监视器连接到Future。但是,我仍然无法弄清楚如何从Future函数中向该事件监视器发送消息。
编辑2:我现在有一些示例代码。我的第一次尝试与此类似:
function myPing(HostName: string): IOmniFuture<boolean>;
begin
Result := Parallel.Future<boolean>(function: boolean
begin
Result := False;
//Do actual ping here... Set Result := True if successful.
end
);
end;
基本功能有效,但不允许我向TOmniEventMonitor发送任何消息。通过将代码更改为:
,我能够使该部分工作function myPing(HostName: string): IOmniFuture<boolean>;
begin
Result := Parallel.Future<boolean>(function: boolean
begin
Result := False;
//Do actual ping here... Set Result := True if successful.
end,
Parallel.TaskConfig.MonitorWith(Form1.OmniEventMonitor1)
);
end;
现在,我可以成功监视OnTaskTerminated事件,但我仍然无法从任务向事件监视器发送消息。通过再次更改我的代码,我可以访问任务本身并使用task.Comm.Send()发送消息,但消息不会到达EventMonitor:
function myPing(HostName: string): IOmniFuture<boolean>;
begin
Result := Parallel.Future<boolean>(function(const task: IOmniTask): boolean
begin
Result := False;
//Do actual ping here... Set Result := True if successful.
task.Comm.Send(0,'Test 1');
end,
Parallel.TaskConfig.MonitorWith(Form1.OmniEventMonitor1)
);
end;
答案 0 :(得分:0)
这是一个关于如何从异步调用中检索函数结果的简单示例。它不使用&#34; OmniEventMonitor&#34;但是在异步调用返回后调用一个函数(&#34; Ping&#34;在PingU.pas中定义,但在这里不重要):
unit MainFormU;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Menus;
type
TPingResultEvent = procedure (const bResult: Boolean) of object;
TOnTerminateTestForm = class(TForm)
LogMemo: TMemo;
MainMenu: TMainMenu;
PingMenu: TMenuItem;
procedure PingMenuClick(Sender: TObject);
private
procedure BackgroundPing (const sServer: String;
const OnResult: TPingResultEvent);
procedure PingResult (const bResult: Boolean);
public
{ Public declarations }
end;
var
OnTerminateTestForm: TOnTerminateTestForm;
implementation
{$R *.dfm}
uses PingU, OtlParallel, OtlTaskControl;
procedure TOnTerminateTestForm.PingMenuClick (Sender: TObject);
var
sServer : String;
begin
if (InputQuery ('Ping computer', 'Computer name:', sServer)) then
if (sServer <> '') then
begin
PingMenu.Enabled := false;
LogMemo.Lines.Add (Format ('Pinging %s',[sServer]));
BackgroundPing (sServer, PingResult);
end; { if }
end; { TOnTerminateTestForm.PingMenuClick }
procedure TOnTerminateTestForm.BackgroundPing (const sServer: String;
const OnResult: TPingResultEvent);
var
bResult : Boolean;
begin
Parallel.Async (
procedure
begin
bResult := Ping (sServer);
end,
Parallel.TaskConfig.OnTerminated(
procedure (const task: IOmniTaskControl)
begin
// executed in main thread after the async has finished
if Assigned (OnResult) then
OnResult (bResult);
end
)
);
end; { TOnTerminateTestForm.BackgroundPing }
procedure TOnTerminateTestForm.PingResult (const bResult: Boolean);
begin
PingMenu.Enabled := true;
LogMemo.Lines.Add ('Ping result = ' + BoolToStr (bResult, true));
end; { TOnTerminateTestForm.PingResult }
end.
代码来源:Get a function result asynchronously in Delphi using Omni Thread Library