德尔福静态阵列线程安全仅与关键部分



我有一个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;

开始时,数组初始化为 enable = 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. 主线程只会将 Enabled 标志从 False 切换到 True
  2. 工作线程只会在相反的方向上切换标志。
  3. 除了我们在这里看到的代码之外,没有其他代码可以访问数组。

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

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

最新更新