我有一个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;
答案 0 :(得分:1)
我认为你的设计就是这样:
Enabled
标记从False
切换为True
。 如果是这样,没有临界区的原始代码已经是线程安全的。至少它是在使用强大内存模型的硬件上。例如Intel x86或x64架构。 Enabled
布尔值充当线程之间的同步障碍。
然而,你的整个设计对我来说都是有缺陷的。 while True
循环和Sleep
会让我有些警觉。该线程无缘无故地重复运行。当主线程对阵列进行修改时,你应该只在线程中执行代码。我更喜欢使用信号(例如Windows事件)来唤醒线程。