1

我有一个 Win32 线程(没有 TThread),它一直运行并迭代一个静态数组。主线程可以修改数组的字段。没有像 TThreadList(对于无 vcl 应用程序)这样的组件,只有 Windows 关键部分(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;
4

1 回答 1

1

在我看来,您的设计是这样的:

  1. 主线程只会将Enabled标志从切换FalseTrue
  2. 工作线程只在相反方向切换标志。
  3. 除了我们在这里看到的代码之外,没有其他代码可以访问该数组。

如果这是真的,那么没有关键部分的原始代码已经是线程安全的。至少它是在使用强内存模型的硬件上。例如 Intel x86 或 x64 架构。Enabled布尔值充当线程之间的同步屏障。

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

于 2012-10-10T12:02:22.753 回答