常に実行され、静的配列を反復処理する Win32 スレッド (TThread なし) があります。メインスレッドは配列のフィールドを変更できます。Windows クリティカル セクション (TRTLCriticalSection) のみを使用して、TThreadList (no-vcl アプリケーションの場合) などのコンポーネントを使用せずに、このスレッド セーフを実現する最善の方法は何ですか?
コード:
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;