Delphi静态数组线程安全仅适用于临界区

时间:2012-10-10 11:36:43

标签: multithreading delphi critical-section static-array

我有一个Win32线程(没有TThread),它在时间上运行并迭代一个静态数组。 mainthread可以修改数组的字段。使用TThreadList (对于no-vcl应用程序),仅使用Windows Critical Sections(TRTLCriticalSection),使这个线程安全的最佳方法是什么?

代码:

type
  T = record
    Idx: Integer;
    Str: string;
    Num: Real;
    Enabled: Boolean;
  end;

var
  A: Array[0..9] of T;
  Cnt: Integer;
  CS: TRTLCriticalSection;

procedure thread;
var
  I: Integer;
begin
  while True do
  begin
    for I := Low(A) to High(A) do
    begin
      if A[I].Enabled then
      begin
        //modify some fields from A[I]

        Inc(A[I].Idx);
        if A[I].Idx >= 10 then
        begin
          A[I].Enabled := False;
          InterlockedDecrement(Cnt);
        end;
      end;
    end;
    if Cnt = 0 then Sleep(1);
  end;
end;

procedure Add(...); //called only from mainthread

  function GetFreeField: Integer;
  begin
    for Result := Low(A) to High(A) do
      if not A[Result].Enabled then Exit;
    Result := -1;
  end;

var
  I: Integer;
begin
  I := GetFreeField;
  if I = -1 then Exit;

  //set fields A[I]

  A[I].Enabled := True;
  InterlockedIncrement(Cnt);
end;

在开始时,使用enabled = false和cnt = 0初始化数组。

以下修改是否足够?

procedure thread;
var
  I: Integer;
begin
  while True do
  begin
    for I := Low(A) to High(A) do
    begin
      EnterCriticalSection(CS);
      if A[I].Enabled then
      begin
        LeaveCriticalSection(CS);
        //modify some fields from A[I]

        Inc(A[I].Idx);
        if A[I].Idx >= 10 then
        begin
          EnterCriticalSection(CS);
          A[I].Enabled := False;
          LeaveCriticalSection(CS);

          InterlockedDecrement(Cnt);
        end;
      end
      else
        LeaveCriticalSection(CS);
    end;
    if Cnt = 0 then Sleep(1);
  end;
end;

procedure Add(...); //called only from mainthread
var
  I: Integer;
begin
  I := GetFreeField;
  if I = -1 then Exit;

  //set fields A[I]

  EnterCriticalSection(CS);
  A[I].Enabled := True;
  LeaveCriticalSection(CS);

  InterlockedIncrement(Cnt);
end;

1 个答案:

答案 0 :(得分:1)

我认为你的设计就是这样:

  1. 主线程只将Enabled标记从False切换为True
  2. 工作线程只会以相反的方向切换标志。
  3. 除了我们在这里看到的代码之外,没有任何代码可以访问数组。
  4. 如果是这样,没有临界区的原始代码已经是线程安全的。至少它是在使用强大内存模型的硬件上。例如Intel x86或x64架构。 Enabled布尔值充当线程之间的同步障碍。

    然而,你的整个设计对我来说都是有缺陷的。 while True循环和Sleep会让我有些警觉。该线程无缘无故地重复运行。当主线程对阵列进行修改时,你应该只在线程中执行代码。我更喜欢使用信号(例如Windows事件)来唤醒线程。