Delphi:如何从 idHTTPServer.OnCommandGet 方法在主线程中执行过程

dur*_*ara 2 delphi multithreading vcl thread-safety idhttp

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

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

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

据我所知,IdHTTPServer 使用线程进行连接 - 和以前一样。但是新的事件处理程序不直接传递 Thread - 所以我不能像 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;
Run Code Online (Sandbox Code Playgroud)

还是我做错了什么?

感谢您的帮助!

Rem*_*eau 6

有一种方法可以访问TThreada TIdContext-背后的底层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;
Run Code Online (Sandbox Code Playgroud)

但是,在你的情况下你实际上并不需要它,因为TThread.Synchronize()(and 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;
Run Code Online (Sandbox Code Playgroud)

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

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;
Run Code Online (Sandbox Code Playgroud)

话虽如此,TIdSync(和TIdNotify) 已被弃用,以支持 支持匿名过程TThreadclass方法重载,例如:

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;
Run Code Online (Sandbox Code Playgroud)

或者:

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;
Run Code Online (Sandbox Code Playgroud)