处理传递给TThread.Queue的匿名过程中的局部变量

时间:2017-02-17 14:53:56

标签: multithreading pascal delphi

我有一个使用Thread执行某些工作的程序。线程应该通知进度的另一个线程(在本例中是主线程)。

如果我使用 Synchronize ()执行同步,一切都按预期工作。如果我与主线程同步并发布for-variable并将其放入列表中,则每个值都会正确打印到我的ListBox中:

procedure TWorkerThread.Execute;
var
  i: Integer;
begin
  inherited;

  for i := 1 to 1000 do
  begin
    Synchronize(
      procedure()
      begin
        FireEvent(i);
      end);
  end;
end;
  

输出:1,2,3,4,5 ... 1000

如果我使用 Queue ()执行同步,则输出不符合预期:

procedure TWorkerThread.Execute;
var
  i: Integer;
begin
  inherited;

  for i := 1 to 1000 do
  begin
    Queue(
      procedure()
      begin
        FireEvent(i);
      end);
  end;
end;
  

输出:200,339,562,934,1001,1001,1001,1001,1001,1001,1001,1001,1001,[...]

这里发生了什么?根据我的理解,匿名程序应该捕获变量" i"?

1 个答案:

答案 0 :(得分:5)

匿名过程捕获变量引用。 这意味着在匿名过程运行时该值未确定。

为了捕获一个值,你必须将它包装成一个独特的框架,如下所示:

Type
  TWorkerThread = class (TThread)
    ...
    function GetEventProc(ix : Integer): TThreadProcedure;
  end;

function TWorkerThread.GetEventProc(ix : Integer) : TThreadProcedure;
// Each time this function is called, a new frame capturing ix 
// (and its current value) will be produced.
begin
  Result := procedure begin FireEvent(ix); end;
end;

procedure TWorkerThread.Execute;
var
  i: Integer;
begin
  inherited;

  for i := 1 to 1000 do
  begin
    Queue( GetEventProc(i));
  end;
end;

另见Anonymous methods - variable capture versus value capture