Multithreading 如何在Delphi中防止线程冻结主应用程序

Multithreading 如何在Delphi中防止线程冻结主应用程序,multithreading,delphi,freeze,Multithreading,Delphi,Freeze,我在做一个德尔福项目。我创建了一个类,它可以帮助我在一个线程内连接到web 我有个问题。此线程将冻结主应用程序,直到收到全部响应。 所以我需要你的帮助来克服这个挑战 Web.pas unit Web; interface uses SysUtils, Classes, IdBaseComponent, Dialogs, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, idMultipartFormData; ty

我在做一个德尔福项目。我创建了一个类,它可以帮助我在一个线程内连接到web

我有个问题。此线程将冻结主应用程序,直到收到全部响应。

所以我需要你的帮助来克服这个挑战

Web.pas

unit Web;

interface

uses
  SysUtils, Classes, IdBaseComponent, Dialogs,
  IdComponent,
  IdTCPConnection,
  IdTCPClient,
  IdHTTP,
  idMultipartFormData;

type
  TCallBack = reference to procedure(res: String);

type
  TWebThread = class(TThread)
  private
    iniRes, iniURL: String;
    iniParams: TStringList;
    iniCallBack: TCallBack;
    Error : String;
    // var iniCallBack: reference to procedure(arg1:string);
  public
    constructor Create(url:String; Params:TStringList; CallBack:TCallBack);
    // destructor Destroy; override;
    procedure Execute(); override;
  end;

implementation

constructor TWebThread.Create(url:String; Params:TStringList; CallBack:TCallBack);
begin

  FreeOnTerminate := True;
  inherited Create(false);

  Self.FreeOnTerminate := True;
  Self.iniURL := url;
  Self.iniCallBack := CallBack;
  Self.iniParams := TStringList.Create;
  iniParams.Assign(Params);

end;


procedure TWebThread.Execute();
var
  lParam: TIdMultipartFormDataStream;
  IHTTP: TIDHTTP;
  i:Integer;
begin

  // inherited;
  IHTTP := TIDHTTP.Create(nil);
  lParam := TIdMultipartFormDataStream.Create;
  IHTTP.Request.UserAgent := 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36';

  for i := 0 to iniParams.Count-1 do
  begin
    lParam.AddFormField(iniParams.Names[i], iniParams.ValueFromIndex[i]);
  end;




  try
    try
      iniRes := IHTTP.Post(iniURL, lParam);

      Synchronize(PROCEDURE
                  BEGIN
                    iniCallBack(iniRes);
                  END);


    Except
      on E: Exception do
        Error := E.ClassName + ' error raised, with message : ' + E.Message;
    end;
  finally
    FreeAndNil(IHTTP);
    FreeAndNil(iniParams);
  end;

end;

end.
下面是如何使用:

procedure TMainForm.Button2Click(Sender: TObject);
var
  Params: TStringList;
  Web: TWebThread;

begin
  Params := TStringList.Create;
  Params.AddPair('Name','Ahmad');
  Params.AddPair('Family','Khaliq');
  Web := TWebThread.Create('http://localhost/get.php', Params,procedure (res : string)
        begin
           Label1.Caption := res;
        end);
  Web.Execute;
end;
这是我的问题: 此线程将冻结主应用程序,直到它收到整个idHTTP响应。我认为(但尚未验证)原因是您对Web的显式调用。从主线程执行

线程的Execute方法应该(并且将自动)从线程本身内部调用,而不是从主线程调用

因此,尝试删除Web。执行调用,看看这是否解决不了您遇到的问题

同步代码提取:

 if (CurrentThread.ThreadID = MainThreadID) and not (QueueEvent and ForceQueue) then
  begin
    if Assigned(ASyncRec.FMethod) then
      ASyncRec.FMethod()
    else if Assigned(ASyncRec.FProcedure) then
      ASyncRec.FProcedure();
  end else

正如HeartWare指出的,永远不要显式调用
Execute
方法。当在
CreateSuspended
设置为false的情况下调用create ctor时,或者在
CreateSuspended
设置为true时调用create后调用
Start
时,将自动调用该函数。请注意,当
FreeOnTerminate
设置为true时,保留对该线程的引用没有意义,因为如果线程已完成,则对该引用的任何访问都可能导致对无效指针的访问。如果没有Web.Execute,则不会发生任何事情。它根本不起作用,您确定您的程序调用继承的Create(false)而不是“true”?如果是这样,线程应该自动调用Execute。尝试在Execute方法的第一行放置一个断点,看看它是否曾经到达那里(应该)。如果是这样的话,sigle会逐步检查代码,看看哪里出了问题。最可能的原因是HTTP请求引发异常,因为您只是简单地将其吞并,并将其分配给一个类变量错误,然后在Execute方法终止时将其释放。谢谢!现在可以了!从主线程调用Execute将导致方法在主线程而不是辅助线程中运行,这不会直接导致冻结。执行中的同步调用是另一回事,不能从主线程调用同步,这可能是最可能的原因。@SertacAkyuz:Synchronize可以从主线程调用(至少在Delphi Rio中)。在这种情况下,直接调用事件/方法,而不是将其放入队列中,以便在主线程中调用。请参见答案中的代码摘录。