我和一位同事争论有关枚举类型的线程安全问题。具有以下简单枚举类型:
type Suit = (Club, Diamond, Heart, Spade);
并在类中声明为变量,如下面的虚拟代码:
type
TTest = class
private
FSuit: Suit;
function SetSuit(aValue: Suit);
public
property GimmeSuit: Suit read FSuit;
.....
function SetSuit(aValue: Suit);
begin
FSuit:= aValue;
end;
我说这段代码是线程安全的,因为设置FSuit变量的值是一个原子操作。我错了吗?我没有在网上找到关于这个案子的任何内容。
答案 0 :(得分:11)
您需要明确使用的术语 threadsafe 和 atomic ,然后才能正确解决。
在您展示的代码中,我假设多个线程都在读取和写入FSuit
。
完成所有这些操作后,读取和写入FSuit
是原子的,只要它是单个字节或对齐。
单字节内存访问始终是原子的。如果枚举类型大于单个字节,则必须将内存读/写对齐为原子。未对齐的内存访问可以撕裂。也就是说,读取线程可能只看到写入的一部分,因为该变量跨越了高速缓存行。写入线程必须将变量的一部分写入一个高速缓存行,然后将其余部分写入相邻的高速缓存行,并且读取线程可以通过两阶段写入过程读取整个变量。
现在,使用默认设置,此枚举类型将是单个字节,并且类布局将对齐。因此,即使对较大的枚举类型进行读/写也是原子的。
至于您的程序是否是线程安全的,无法从此处的信息中确定。你需要澄清意图是什么。例如,假设两个线程写入FSuit
,第三个线程从中读取。如果程序的正确性不依赖于那些内存访问的顺序,那么它就是线程安全的。如果它的正确性取决于排序,则它不是线程安全的并且需要同步。