在我的应用程序中,有几个线程增加了一些计数器,只有一个线程读取这个值(主线程)。据我所知,如果以双字对齐,读取32位值是线程安全的,因此我使用以下代码:
{$A8}
TMyStat = class
private
FCounter: Integer;
public
procedure IncCounter;
property Counter: Integer read FCounter;
...
procedure TMyStat.IncCounter;
begin
InterlockedIncrement(FCounter);
end;但我不确定将Interlocked函数与直接访问值混合使用是否安全。
我应该用InterlockedCompareExchange代替吗?
function TMyStat.GetCounter: Integer;
begin
Result := InterlockedCompareExchange(FCounter, 0, 0);
end;发布于 2018-02-12 12:40:41
你可以用普通读物。由于FCounter是4对齐的,所以读写保证是原子化的.
不过,对于英特尔平台来说,这是可行的。我真的不知道手臂是怎么表现的。我猜想这种行为是一样的(对齐值的读取是原子的)。
实际上,如果您只增加一个计数器并读取它,您甚至不需要InterlockedIncrement。当您读取该值时,您将始终得到增量前或增量后的值。你不可能两者兼而有之。
发布于 2018-02-13 14:53:51
读取对齐的32位值是原子的(也就是说,所有32位都保证是一致的)。但是读取不是同步的。您可能不会读取“当前”值,而是从缓存中读取一个值。
例如:
FCounter := 1; //number of threads running
FResult := 0; //the answer to everything然后你的线:
procedure ThreadProc;
begin
FResult := 42; //set the answer before we indicate we're done
InterlockedDecrement(FCounter);
end;然后,代码检查线程是否已完成:
if (FCounter <= 0) then
begin
//Thread is done; read the answer
ShowMessage('The answer is: '+IntToStr(FResult));
Exit;
end;答案是:0
即使您的标志说线程设置了结果,您也可以从本地缓存中读取结果值。
FCounter和FResult的读取是原子的如果您只使用FCounter,那么您就没事了。但是,一旦您使用其他任何东西并期望它们是一致的,那么您还需要使用一些东西来强制同步。
对您的问题的严格回答是,读取32位对齐值已经是一个原子操作。
但是,完全有可能的是,来到这里阅读这个问题的人们可能会忘记,读到的原子是你所担心的一小部分。
https://stackoverflow.com/questions/48746109
复制相似问题