为什么这段代码会阻塞我的主线程?

时间:2014-04-21 05:17:54

标签: multithreading delphi

我需要独立于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

2 个答案:

答案 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;