【问题标题】:Delphi: how to execute procedure in main thread from idHTTPServer.OnCommandGet methodDelphi:如何从 idHTTPServer.OnCommandGet 方法在主线程中执行程序
【发布时间】:2020-12-04 15:37:19
【问题描述】:

我必须在我们的应用程序中创建一个嵌入式 HTTP 服务器。 必须为进程间通信创建这个,因为对方只能调用WebService。

我们不需要一次处理更多请求,但我必须使用主线程中的库和数据库连接。

Delphi 版本是 Seattle,Indy 版本是 10(内部)。

据我所知,IdHTTPServer 像以前一样使用线程进行连接。 但是新的事件处理程序不直接传递线程 - 所以我不能像 N 年前那样调用 TThread.Synchronize。 而且我没有找到任何方法来获取线程。

在某处我读到 TIdSync 或 TIdNotify 类可以帮助我。我找不到任何完整的例子来看看如何。

查看这个简单的代码。在主线程中完成我的工作就足够了吗?

procedure TForm5.IdHTTPServer1CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo;
    AResponseInfo: TIdHTTPResponseInfo);
begin
    FURI := ARequestInfo.URI; // Store the URI for main thread access
    FResult := '';
    TIdSync.SynchronizeMethod(Self.ProcessIt); // Call sync to process in VCL thread
    AResponseInfo.ContentText := FResult; // This variable contains the result
end;

还是我做错了什么?

感谢您的帮助!

dd

【问题讨论】:

  • 为什么不能调用TThread.Syncronize
  • @DelphiCoder OP 可能不知道Synchronize()class 方法重载,它不需要TThread 对象来调用它。

标签: multithreading delphi thread-safety vcl idhttp


【解决方案1】:

有一种方法可以访问TIdContext 后面的底层TThread - 将TIdContext.Yarn 属性类型转换为TIdYarnOfThread,然后访问其Thread 属性,例如:

procedure TForm5.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  Thread: TThread;
begin
  Thread := (AContext.Yarn as TIdYarnOfThread).Thread;
  FURI := ARequestInfo.URI;
  FResult := '';
  Thread.Synchronize(ProcessIt);
  AResponseInfo.ContentText := FResult;
end;

但是,在您的情况下,您实际上并不需要它,因为TThread.Synchronize()(和TThread.Queue())具有class 方法重载,因此您不需要TThread 对象来调用它,例如:

procedure TForm5.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
  FURI := ARequestInfo.URI;
  FResult := '';
  TThread.Synchronize(nil, ProcessIt);
  AResponseInfo.ContentText := FResult;
end;

TIdSync(和TIdNotify)确实可以用来代替,你所拥有的是一个好的开始,它只需要再充实一点,以便访问你的FURI和@987654338 @ variables 也是同步的,以防您一次需要处理多个客户端连接,因此需要避免对变量的并发访问,例如:

type
  TIdProcessItSync = class(TIdSync)
    URI: string;
    Content: string;
  protected
    procedure DoSynchronize; override;
  end;

procedure TIdProcessItSync.DoSynchronize;
begin
  Content := Form5.ProcessIt(URI);
end;

function TForm5.ProcessIt(const URI: string): String;
begin
  Result := ...;
end;

procedure TForm5.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  Sync: TIdProcessItSync;
begin
  Sync := TIdProcessItSync.Create;
  try
    Sync.URI := ARequestInfo.URI;
    Sync.Synchronize;
    AResponseInfo.ContentText := Sync.Content;
  finally
    Sync.Free;
  end;
end;

话虽如此,TIdSync(和TIdNotify)已被弃用,而支持TThreadclass 方法重载支持anonymous procedures,例如:

function TForm5.ProcessIt(const URI: string): String;
begin
  Result := ...;
end;

procedure TForm5.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  URI, Content: String;
begin
  URI := ARequestInfo.URI;
  TThread.Synchronize(nil, 
    procedure
    begin
      Content := ProcessIt(URI);
    end
  );
  AResponseInfo.ContentText := Content;
end;

或者:

function TForm5.ProcessIt(const URI: string): String;
begin
  Result := ...;
end;

procedure TForm5.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
  TThread.Synchronize(nil, 
    procedure
    begin
      AResponseInfo.ContentText := ProcessIt(ARequestInfo.URI);
    end
  );
end;

【讨论】:

  • 亲爱的雷米!这是一个很好的例子!非常非常感谢! :-)
猜你喜欢
  • 2017-06-19
  • 2012-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多