使用Delphi XE7并行库

时间:2014-11-14 21:34:37

标签: multithreading delphi parallel-processing tthread

我有一个耗时的例程,我想使用Delphi XE7的新并行库并行处理。

以下是单线程版本:

procedure TTerritoryList.SetUpdating(const Value: boolean);
var
  i, n: Integer;
begin
  if (fUpdating <> Value) or not Value then
  begin
    fUpdating := Value;

    for i := 0 to Count - 1 do
    begin
      Territory[i].Updating := Value; // <<<<<< Time consuming routine
      if assigned(fOnCreateShapesProgress) then
        fOnCreateShapesProgress(Self, 'Reconfiguring ' + Territory[i].Name, i / (Count - 1));
    end;
  end;
end;

实际上并没有什么复杂的事情发生。如果区域列表变量已更改或设置为false,则例程将循环遍历所有销售区域并重新创建区域边界(这是一项耗时的任务)。

所以这是我试图让它并行:

procedure TTerritoryList.SetUpdating(const Value: boolean);
var
  i, n: Integer;
begin
  if (fUpdating <> Value) or not Value then
  begin
    fUpdating := Value;

    n := Count;
    i := 0;

    TParallel.For(0, Count - 1,
      procedure(Index: integer)
      begin
        Territory[Index].Updating := fUpdating; // <<<<<< Time consuming routine
        TInterlocked.Increment(i);
        TThread.Queue(TThread.CurrentThread,
          procedure
            begin
              if assigned(fOnCreateShapesProgress) then
                fOnCreateShapesProgress(nil, 'Reconfiguring ', i / n);
            end);
      end
    );
  end;
end;

我用并行for循环替换了for循环。计数器'i'被锁定,因为它增加以显示进度。然后我将OnCreateShapeProgress事件包装在TThread.Queue中,该事件将由主线程处理。 OnCreateShapeProgress事件由一个例程处理,该例程更新描述任务的进度条和标签。

如果我排除了对OnCreateShapeProgress事件的调用,则例程有效。它因EAurgumentOutOfRange错误而崩溃。

所以我的问题很简单:

我做任何蠢事吗?

如何从TParallel.For循环或TTask中调用事件处理程序?

1 个答案:

答案 0 :(得分:4)

我能看到的最明显的问题是你排队到工作线程。

您对TThread.Queue的来电通过TThread.CurrentThread。这就是你打电话给TThread.Queue的主题。我认为你绝不应该将TThread.CurrentThread传递给TThread.Queue,这是安全的。

相反,删除该参数。使用只接受线程过程的one参数重载。

否则我会注意到进度计数器i的递增并未真正正确处理。好吧,增量很好,但是你稍后再读它就是一场比赛。如果线程1在线程2之前递增但线程2在线程1之前排队进度,则可以无序地报告进度。通过将计数器增量代码移动到主线程来解决此问题。只需在排队的匿名方法中增加它。额外的奖励是你不再需要使用原子增量,因为所有修改都在主线程上。

除此之外,此质量控制报告似乎与您报告的内容非常相似:http://qc.embarcadero.com/wc/qcmain.aspx?d=128392

最后,AtomicIncrement是在最新版本的Delphi中执行无锁递增的惯用方法。