首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >线程安全读取InterlockedIncremented值

线程安全读取InterlockedIncremented值
EN

Stack Overflow用户
提问于 2018-02-12 12:04:45
回答 2查看 240关注 0票数 1

在我的应用程序中,有几个线程增加了一些计数器,只有一个线程读取这个值(主线程)。据我所知,如果以双字对齐,读取32位值是线程安全的,因此我使用以下代码:

代码语言:javascript
运行
复制
{$A8}
TMyStat = class
private
  FCounter: Integer;
public
  procedure IncCounter;
  property Counter: Integer read FCounter;
...

procedure TMyStat.IncCounter;
begin
  InterlockedIncrement(FCounter);
end;

但我不确定将Interlocked函数与直接访问值混合使用是否安全。

我应该用InterlockedCompareExchange代替吗?

代码语言:javascript
运行
复制
function TMyStat.GetCounter: Integer;
begin
  Result := InterlockedCompareExchange(FCounter, 0, 0);
end;
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-02-12 12:40:41

你可以用普通读物。由于FCounter是4对齐的,所以读写保证是原子化的.

不过,对于英特尔平台来说,这是可行的。我真的不知道手臂是怎么表现的。我猜想这种行为是一样的(对齐值的读取是原子的)。

实际上,如果您只增加一个计数器并读取它,您甚至不需要InterlockedIncrement。当您读取该值时,您将始终得到增量前或增量后的值。你不可能两者兼而有之。

票数 3
EN

Stack Overflow用户

发布于 2018-02-13 14:53:51

读取对齐的32位值是原子的(也就是说,所有32位都保证是一致的)。但是读取不是同步的。您可能不会读取“当前”值,而是从缓存中读取一个值。

例如:

代码语言:javascript
运行
复制
FCounter := 1; //number of threads running
FResult  := 0; //the answer to everything

然后你的线:

代码语言:javascript
运行
复制
procedure ThreadProc;
begin
   FResult := 42; //set the answer before we indicate we're done
   InterlockedDecrement(FCounter);
end;

然后,代码检查线程是否已完成:

代码语言:javascript
运行
复制
if (FCounter <= 0) then
begin
   //Thread is done; read the answer
   ShowMessage('The answer is: '+IntToStr(FResult));
   Exit;
end;

答案是:0

即使您的标志说线程设置了结果,您也可以从本地缓存中读取结果值。

  • 尽管FCounterFResult的读取是原子的
  • 它们不是同步的

如果您只使用FCounter,那么您就没事了。但是,一旦您使用其他任何东西并期望它们是一致的,那么您还需要使用一些东西来强制同步。

对您的问题的严格回答是,读取32位对齐值已经是一个原子操作。

但是,完全有可能的是,来到这里阅读这个问题的人们可能会忘记,读到的原子是你所担心的一小部分。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48746109

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档