如何在并行线程中显示进度

时间:2015-08-31 09:16:59

标签: multithreading delphi parallel-processing

我有这样的代码:

procedure TSeries.Read;
var
 ReadProc: TParallelFunction2;
 Counter:  integer;
begin
 try
  ProgressForm.Show;
  Counter  := 0;
  ReadProc :=
   procedure (i1, i2, tdi: integer)
   var
    i: integer;
   begin
    for i := i1 to i2 do
     if not FDASlice[i].PctPresent then
     begin
      TInterlocked.Increment(Counter);
      ReadSlice(i, True);
     end;
   end;

  Parallel.ForI(0, High, ReadProc, pfDivide);
 finally
  ProgressForm.HideForm;
 end;
end;

它使用STParallel库在多线程模式下处理ReadProc过程。一切正常,但我需要向用户显示进度。 我尝试将'Application.ProcessMessage'+'ProgressForm.SpTBXProgressBar1.Position:= Counter'添加到ReadProc中,或者'TThread.Synchronize'没有成功。应用程序挂起,进度未显示。

我如何才能显示进度?是否有可能在该代码中,或者需要将所有非主线程移动到其他位置?谢谢。

1 个答案:

答案 0 :(得分:5)

处理此问题的最简单,最好的方法是让主线程更新计时器的进度。

您需要为进度计数器提供计时器事件访问权限。这意味着将Counter变量从局部变量转换为UI可以访问的类的变量。您不需要同步对计数器的访问,因为UI没有修改它,并且您已经使用原子增量函数来修改计数器。

因此,您需要的步骤是:

  1. Counter变量移动为类的成员,UI可以访问该类。
  2. 以适当的更新频率向UI添加计时器。定时器间隔为100毫秒就足够了。
  3. 在计时器事件中,将进度条的位置设置为计数器的瞬时值。
  4. 那为什么这种方法比你的更好?好吧,进度UI更新不应该由工作线程驱动。这样做会冒着刷新UI的风险。这可能严重阻碍性能和可扩展性。

    让工作人员更新进度状态,但让UI继续负责驱动更新。 UI知道没有太频繁刷新的点,只有它能够确定刷新率。