我需要独立于Thread
的{{1}}作品。
例如,我的Form
:
Thread
现在,当我点击procedure TCustomThread.doProc;
begin
repeat
.
.
.
until (1 = 2);
end;
procedure TCustomThread.Execute;
begin
inherited;
Synchronize(doProc);
end;
.
.
.
procedure TForm1.Button1Click(Sender: TObject);
var
thrd : TCustomThread;
begin
thrd := TCustomThread.Create(True);
thrd.Resume;
Application.ProcessMessages;
end;
时,Button1
会运行,但主Thread
已被锁定。如何避免暂停Form
?
答案 0 :(得分:9)
对ProcessMessages
的调用是错误的,应该删除。作为一个广泛而一般的规则,应避免调用ProcessMessages
。而这个根本没有任何意义。
其余代码只运行一个非终止循环。它使用Synchronize
来确保非终止循环在主线程上运行。因此主线程无法为其消息循环提供服务。
线程的全部目的是能够执行单独的执行线程。通过使用Synchronize
,您将在主线程中运行所有代码。您的代码相当于将非终止循环放在主线程中。
您希望在不同的线程中执行代码。所以你应该避免拨打Synchronize
。这应该仅用于必须在主线程上执行的小型,快速的工作。通常是GUI更新。
你的执行方法应该是:
procedure TCustomThread.Execute;
begin
while not Terminated do
begin
....
end;
end;
这引入了你的循环,但循环现在在线程中执行。您现在可以在循环体内添加线程的有用代码。
请记住,必须在主线程上使用任何VCL组件。这就是使用Synchronize
的地方。
答案 1 :(得分:0)
TThread.Synchronize()
在主线程的上下文中运行指定的过程,而不是在工作线程的上下文中。所以你的循环在主线程中运行,并且不让主线程处理来自其消息队列的新消息。这就是为什么你的UI在线程运行时没有响应的原因。
你需要将你的线程重组为更像这样的东西:
procedure TCustomThread.doUpdateUI;
begin
... do something that updates the UI here ...
end;
procedure TCustomThread.Execute;
begin
while not Terminated do
begin
... do something in the worker thread ...
Synchronize(doUpdateUI);
... do something else in the worker thread ...
end;
end;
var
thrd : TCustomThread = nil;
procedure TForm1.Button1Click(Sender: TObject);
begin
if thrd = nil then
thrd := TCustomThread.Create(False);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if thrd <> nil then
begin
thrd.Terminate;
thrd.WaitFor;
FreeAndNil(thrd);
end;
end;