Multithreading 如何在Delphi中防止线程冻结主应用程序
我在做一个德尔福项目。我创建了一个类,它可以帮助我在一个线程内连接到web 我有个问题。此线程将冻结主应用程序,直到收到全部响应。 所以我需要你的帮助来克服这个挑战 Web.pasMultithreading 如何在Delphi中防止线程冻结主应用程序,multithreading,delphi,freeze,Multithreading,Delphi,Freeze,我在做一个德尔福项目。我创建了一个类,它可以帮助我在一个线程内连接到web 我有个问题。此线程将冻结主应用程序,直到收到全部响应。 所以我需要你的帮助来克服这个挑战 Web.pas unit Web; interface uses SysUtils, Classes, IdBaseComponent, Dialogs, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, idMultipartFormData; ty
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中)。在这种情况下,直接调用事件/方法,而不是将其放入队列中,以便在主线程中调用。请参见答案中的代码摘录。