1

TIdHTTPServer由于某些原因,我需要将一个实例放入 DLL 中。它是这样完成的:

接口单元:

unit DLL.Intf;

interface

type
  IServer = interface
    procedure DoSomethingInterfaced();
  end;

implementation

end.

服务器的容器:

unit Server;

interface

uses
  DLL.Intf,
  IdHTTPServer,
  IdContext,
  IdCustomHTTPServer;

type
  TServer = class(TInterfacedObject, IServer)
  private
    FHTTP: TIdHTTPServer;
    procedure HTTPCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo;
      AResponseInfo: TIdHTTPResponseInfo);
    procedure DoSomethingInterfaced();
  public
    constructor Create();
    destructor Destroy(); override;
  end;

function GetInstance(): IServer;

implementation

uses
  SysUtils;

var
  Inst: IServer;

function GetInstance(): IServer;
begin
  if not Assigned(Inst) then
    Inst := TServer.Create();

  Result := Inst;
end;

constructor TServer.Create();
begin
  inherited;
  FHTTP := TIdHTTPServer.Create(nil);
  FHTTP.OnCommandGet := HTTPCommandGet;
  FHTTP.Bindings.Add().SetBinding('127.0.0.1', 15340);
  FHTTP.Active := True;
end;

destructor TServer.Destroy();
begin
  FHTTP.Free();
  inherited;
end;

procedure TServer.DoSomethingInterfaced();
begin

end;

procedure TServer.HTTPCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo;
  AResponseInfo: TIdHTTPResponseInfo);
begin
  AResponseInfo.ContentText := '<html><h1>HELLO! ' + IntToStr(Random(100)) + '</h1></html>';
end;

end.

DLL 导出GetInstance()函数:

library DLL;

uses
  SysUtils,
  Classes,
  Server in 'Server.pas',
  DLL.Intf in 'DLL.Intf.pas';

{$R *.res}

exports
  GetInstance;

begin
end.

服务器加载并正常工作,直到我退出主 EXE 文件。调试器显示主线程挂起FHTTP.Free();

我认为我不需要担心线程同步,因为我对 EXE 和 DLL 项目都使用了“使用运行时包构建”选项。

我该如何解决这个挂起?

4

2 回答 2

2

我的解决方案是在关闭我的应用程序的主窗体时将Active属性设置为TIdHTTPServerfalse

我猜服务器必须在退出消息循环之前停止其所有线程并与主线程同步。

如果它可以解释背后的机制,我会检查另一个答案是否正确。

于 2012-09-14T11:04:59.973 回答
1

只有当您的代码与事件内部的主线程同步时,您所描述的才会发生TIdHTTPServer,例如OnCommandGet. 但是在您显示的代码中并没有这样做,因此应该没有任何东西阻止TIdHTTPServer析构函数正常退出。在内部,析构函数确实将该Active属性设置为 False,它会等待任何活动线程完全终止。内部没有任何东西TIdHTTPServer与主线程同步。TIdHTTPServer在与主线程同步时从主线程停用会导致死锁(调用也会导致死锁)TThread.Synchronize()如果运行时包被禁用,通常在 DLL 中,你说它们不是)。所以你描述的没有意义。您只需通过调试器中的 TIdHTTPServer 析构函数即可找到实际的死锁。

于 2012-09-14T23:04:11.333 回答