Delphi中的整数读取是原子的吗?

Posted

技术标签:

【中文标题】Delphi中的整数读取是原子的吗?【英文标题】:Are integer reads atomic in Delphi? 【发布时间】:2015-04-30 02:49:25 【问题描述】:

对于从 XE2 到 XE8 的 Delphi 编译器,对于非 Windows 目标平台,是否是整数数据成员的读取操作,用 [Volatile] 注释,原子?

我知道对于 windows 平台的情况,当且仅当数据成员对齐到 4 个字节时它是原子的,但是非 windows(android 等)呢?

请注意,我不是在询问线程安全。线程安全和原子性是两个不同的东西。

【问题讨论】:

@Ken-White:请重新打开。这个问题不是重复的。 见Atomic vs. Non-Atomic Operations。 "In practice, we usually know more about our target platforms than that. For example, it’s common knowledge that on all modern x86, x64, Itanium, SPARC, ARM and PowerPC processors, plain 32-bit integer assignment is atomic as long as the target variable is naturally aligned. You can verify it by consulting your processor manual and/or compiler documentation. In the games industry, I can tell you that a lot of 32-bit integer assignments rely on this particular guarantee." 这取决于对内存的写入周期数。一个循环是原子的,而不止一个则不是。 @LURD 。谢谢卢。您的评论是正确答案。 【参考方案1】:

LU RD 的评论是正确答案。

Non-windows 的工作方式与 windows 类似,因为当且仅当数据成员是 32 位对齐时,读取操作是原子的。在一般情况下,您不能依赖它是原子的,因为您不知道对齐方式,但在特定情况下,您可以控制数据成员的声明,您可以使用 $ALIGN 4 或 $ALIGN 8 本地指令以保证对齐。

例子,

$IFDEF POSIX
$ALIGN 4
type
TMyClass = class
  [Volatile] FValue: integer;
  end;
$ENDIF

... 在上面,FValue 可以被原子读取。 (不对线程安全提出任何声明)。

在更一般的情况下,FValue 的对齐方式是未知的,读取 FValue 可能并不总是原子的,并且需要类似于以下代码的内容...

ReadOfValue := TInterlocked.CompareExchange( FValue, 0, 0);

上面有一个警告:TInterlocked 类可能对某些编译器不可用。我不确定它是什么时候引入的。可能是 XE7。


更新

感谢下面来自 David Heffernan 和 Gabr 的 cmets,我声明上面的代码不会在非 Windows 平台上可靠地工作。保证正确对齐的唯一方法是使用指针算法。 OmniThreadLibrary 中的 GpStuff 单元有效地使用指针算法来提供原子可读的整数值。

[Volatile] 属性可能没有帮助,但您也可以说它没有害处,甚至可能有语义上的好处或代码阅读器。

【讨论】:

在类或记录中对齐字段是不够的。包含结构、类或记录也必须对齐。编译器为自动变量提供什么保证?据我所知没有。可悲的是,这是一个完全缺乏语言定义并且实施很差的领域。 @DavidHeffernan 天哪!这是对 $ALIGN 的悲观解释。我理解的记录,但是对于类,如果 $ALIGN 只保证相对于对象基的字段对齐,而不是绝对地址,如您所建议的,那么这使得 $ALIGN 对类完全没有意义。在线帮助说`类中的字段结构在双字边界上对齐`。我想这是可以解释的。我将尝试在 Embarcadero 论坛进行澄清。 无论如何你都不应该使用 $ALIGN 4。你不想要那个。例如,您不想错位双打。您需要默认选项 $ALIGN ON,等于 $ALIGN 8。Embarcadero 对此的记录很差,并且实施得很差。堆分配结构的对齐方式由内存管理器设置确定。默认情况下为 8 IIRC。对于自动存储,我认为您会发现对齐 8 的类型完全有可能,例如双,错位。尝试声明一些双重局部变量,并与一些布尔值混合。 您可以在 Embarcadero 论坛上提问,但有人在那里吗?我的意见是,如果你在这里问,你会得到更好的答案。更重要的是,人们可以在未来受益。否则其他人注定会一次又一次地问同样的问题。 如果值未正确对齐,TInterlocked 将无济于事。即使在 Windows 上,如果对齐不正确,任何 Interlocked* 函数的行为都是未定义的。

以上是关于Delphi中的整数读取是原子的吗?的主要内容,如果未能解决你的问题,请参考以下文章

C/C++ 中的结构赋值是原子的吗?

C++ 对 int 的读写是原子的吗?

mmap 是原子的吗?

我可以假设 Delphi NOW 函数是线程安全的吗?

POSIX 的 read() 和 write() 系统调用是原子的吗?

delphi中,如何读取一个目录中的所有文件?在线等……