线程可以安全地读取由VCL事件设置的变量吗?

时间:2010-04-08 14:23:07

标签: multithreading delphi

线程读取由Delphi VCL事件设置的变量是否安全?

当用户点击VCL TCheckbox时,主线程会将一个布尔值设置为复选框的Checked状态。

CheckboxState := CheckBox1.Checked;

任何时候,线程都会读取该变量

if CheckBoxState then ...

如果线程“错过”对布尔值的更改,则无关紧要,因为线程会检查循环中的变量,因为它会执行其他操作。所以最终会看到状态变化......

这样安全吗?或者我需要特殊代码?围绕变量的读写(分别在线程和主线程中)是否需要充分的关键代码调用?

正如我所说的,如果线程获得“错误”值并不重要,但我一直认为如果一个线程在主线程位于其中时尝试读取变量,则可能存在低级问题写作的中间,反之亦然。

我的问题与此类似:Cross thread reading of a variable who's value is not considered important

(也与我之前的问题相关:Using EnterCriticalSection in Thread to update VCL label

3 个答案:

答案 0 :(得分:6)

这是安全的,原因有三:

  • 只有一个线程写入变量。

  • 变量只有一个字节,因此无法读取不一致的值。它将被视为TrueFalse。 Delphi boolean值不存在对齐问题。

  • Delphi编译器不会对变量是否实际写入进行广泛检查,如果没有,则不会“优化”任何代码。将始终读取非局部变量,不需要volatile说明符。

话虽如此,如果您对此确实不确定,可以使用integer值而不是布尔值,并使用InterlockedExchange()函数写入变量。这在这方面有点过头了,但这是一个很好的技术,因为对于单机字大小的值,它可以消除锁的需要。

您还可以通过适当的同步原语(如事件)替换boolean,并在其上设置线程块 - 这将有助于消除线程中的繁忙循环。

答案 1 :(得分:3)

在您的情况下(Checked属性),读取操作是原子的,因此它是安全的。这与TThread.Terminated属性相同;正确对齐的字节,单词和双字的简单读写操作是原子的。您可以查看intel documentation以获取更多信息:

第8章 - 多处理器管理

8.1.1保证原子操作

Intel486处理器(以及更新的处理器)保证以下内容 基本的内存操作将始终以原子方式执行:

  • 读取或写入字节
  • 读取或写入在16位边界上对齐的字
  • 读取或写入在32位边界上对齐的双字

Pentium处理器(以及更新的处理器)保证以下内容 额外的内存操作将始终以原子方式执行:

  • 读取或写入在64位边界上对齐的四字
  • 16位访问适合32位数据总线的未缓存内存位置

答案 2 :(得分:1)

对于您给出的示例,它将是安全的。从技术上讲,主要问题是你的变量超过机器字大小,因此你可能会得到高字和长字不同步。但是对于较小的值,这不是问题。

如果您认为这是一个潜在的问题,例如使用指针,那么要使用的是TCriticalSection来控制对项目的读取和写入。这对于所有实际情况都足够快,并确保您100%安全。