【问题标题】:Wait for thread without freezing the application等待线程而不冻结应用程序
【发布时间】:2013-05-30 06:48:18
【问题描述】:

我正在尝试将 indy TIdHttp 放入线程中, 我试过这个:

type
  TSendThread = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  public
    http : TIdHTTP;
    URL : String;
    Method : String;
    property ReturnValue;
  end;

procedure TSendThread.Execute;
begin
  form1.Memo1.lines.Add(http.Get(URL));
  ReturnValue := 1;
end;

主要是:

procedure TForm1.Button1Click(Sender: TObject);
var t : TSendThread;
begin
  t := TSendThread.Create(true);
  t.URL := 'http://www.url.com/';
  t.http := http;
  t.Start;
  showmessage(IntToStr(t.ReturnValue));
end;

我的问题是下一条指令在没有等待线程完成的情况下被执行(showmessage),我尝试使用“WaitFor”但它冻结了应用程序。

还有其他解决方法吗?

谢谢。

【问题讨论】:

  • 如果您正在“等待它”完成,则无需首先将其放入线程中。线程用于在后台执行,以便 UI 不必 等待。
  • @Benjamin:如果您必须使用ProcessMessages,那么您现在添加了一个新问题。这从来都不是正确的解决方案。
  • ProcessMessages 谨慎使用是可以的
  • @OnTheFly-ProcessMessages 可能导致意外行为。特别是在使用 TTimer 的冻结应用程序中使用时。

标签: multithreading delphi indy


【解决方案1】:

使用TThread.OnTerminate 事件知道线程何时结束:

type
  TSendThread = class(TThread)
  private
    http : TIdHTTP;
    Line: string;
    procedure AddLine;
  protected
    procedure Execute; override;
  public
    constructor Create; reintroduce;
    destructor Destroy; override;
    URL : String;
    Method : String;
    property ReturnValue;
  end;

constructor TSendThread.Create;
begin
  inherited Create(True);
  FreeOnTerminate := True;
  http := TIdHTTP.Create;
end;

destructor TSendThread.Destroy;
begin
  http.Free;
  inherited;
end;

procedure TSendThread.Execute;
begin
  Line := http.Get(URL);
  Synchronize(AddLine);
  ReturnValue := 1;
end;

procedure TSendThread.AddLine;
begin
  Form1.Memo1.Lines.Add(Line);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  t : TSendThread;
begin
  t := TSendThread.Create;
  t.URL := 'http://www.url.com/';
  t.OnTerminate := ThreadTerminated;
  t.Start;
end;

procedure TForm1.ThreadTerminated(Sender: TObject);
begin
  ShowMessage(IntToStr(TSendThread(Sender).ReturnValue));
end;

如果你想使用循环等待线程完成,而不阻塞 UI,那么你可以这样做:

constructor TSendThread.Create;
begin
  inherited Create(True);
  //FreeOnTerminate := True; // <-- remove this
  http := TIdHTTP.Create;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  t : TSendThread;
  h : THandle;
begin
  t := TSendThread.Create;
  try
    t.URL := 'http://www.url.com/';
    t.Start;
    h := t.Handle;
    repeat
      case MsgWaitForMultipleObjects(1, h, 0, INFINITE, QS_ALLINPUT) of
        WAIT_OBJECT_0:   Break;
        WAIT_OBJECT_0+1: Application.ProcessMessages;
        WAIT_FAILED:     RaiseLastOSError;
      else
        Break;
      end;
    until False;
    ShowMessage(IntToStr(t.ReturnValue));
  finally
    t.Free;
  end;
end;

【讨论】:

  • 是的,我也是这样做的 :)。非常感谢,找了2天了
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-03
  • 2019-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多