主线程阻塞并行线程?

用户名

创建一个VCL窗体应用程序,在窗体上放置一个TButton和一个TMemo,并将此代码写入按钮的OnClick处理程序中:

uses
  OtlParallel, OtlTaskControl;

procedure TForm2.btnStartLoopClick(Sender: TObject);
var
  starttime: Cardinal;
  k: Integer;
begin
  mmoTest.Lines.Clear;
  for k := 1 to 50 do
    mmoTest.Lines.Add('Line ' + IntToStr(k));

  starttime := GetTickCount;
  Parallel.Async(
    procedure
    var
      i: Integer;
    begin
      for i := 1 to 50 do
      begin
        Sleep(100);
        mmoTest.Lines[i - 1] := mmoTest.Lines[i - 1] + FormatDateTime(' nn:ss:zzz', Now);
      end;
    end,
    Parallel.TaskConfig.SetPriority(TOTLThreadPriority.tpHighest).OnTerminated(
    procedure
    begin
      mmoTest.Lines.Add(IntToStr(GetTickCount - starttime) + ' milliseconds');
    end));
end;

现在运行程序并进行以下测试:

  1. 单击按钮,只需等待循环完成,然后查看备忘录最后一行中显示的时间即可:大约为5300毫秒。

  2. 现在,再次单击该按钮,单击并按住表单的标题栏,然后快速移动表单直到循环结束。现在,再次查看备忘录的最后一行:在我的测试中,时间超过了7000毫秒。显然,主线程正在阻塞并行线程!

那么如何避免主线程阻塞并行线程呢?

雷米·勒博

首先,此代码不是线程安全的,因为异步代码直接TMemo从主UI线程外部的任务线程访问你不能这样做。工作线程必须与UI线程同步,以便安全地访问UI控件,否则可能会发生不良情况。您可以使用TThread.Synchronize()TThread.Queue()IOmniTask.Invoke()进行同步。

其次,当您在标题栏上按住鼠标时,主UI消息循环将被阻止(操作系统将运行单独的模式消息循环,直到您松开鼠标为止)。这样,在OnTerminate主消息循环重新获得控制之前,任务的事件处理程序可能不会运行。这就是为什么计时器持续时间比预期长的原因,而不是因为任务循环被阻止了。

第三,Sleep()不是绝对的。它将休眠至少要求的时间,但可能会休眠更长的时间。因此,您的任务循环将运行至少5秒钟,但可能会更长一些。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章