我有一个用Delphi10创建的Delphi (Windows)应用程序,它有一些阻塞调用,我想使用线程来转换。不幸的是,对我来说,这些不是过程,而是函数。(关于如何从线程返回函数结果的信息似乎要有限得多。)我正在努力熟悉OmniThreadLibrary,因为它似乎是Delphi中最灵活和最受支持的线程库,但我在理解如何做到这一点上遇到了麻烦。
我已经能够让各种OmniThreadLibrary例程与过程很好地协同工作,但是当我尝试设置一个函数时,我得到了一个关于捕获结果的错误。当我使用OmniThreadLibrary的Future示例作为起点时,我可以让函数工作,但我不知道如何连接到事件监视器,如何从任务发送消息等。因此,无论我试图以哪种方式解决这个问题,似乎都忽略了一些东西。
目前,我的程序是这样做的:
If myPing(IPAddress) then
begin
//Do other things here…
end;因为myPing正在阻塞,而我实际上需要等待它,直到myPing返回true才能进一步处理,所以应用程序在这个过程中变得缓慢。我想将myPing调用放在一个线程中,这样可以解决速度慢的问题,但我不知道如何使用OmniThreadLibrary以函数的形式实现这一点。(除非我使用的是future,在这种情况下,我不知道如何连接到事件监视程序。)
编辑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;发布于 2017-02-24 00:26:02
下面是一个关于如何从异步调用中检索函数结果的简单示例。它不使用"OmniEventMonitor“,而是在异步调用返回后调用一个函数("Ping”是在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
https://stackoverflow.com/questions/42372198
复制相似问题