TThread的后代,如何从主线程访问属性

3

我有一个继承自TThread的类。我有一些只读的公共属性。如果我的主线程在线程活动时读取这些值,会遇到问题吗?

3个回答

8
如果您所说的“只读属性”是指TThread派生类本身也不会更改它们,并且尽快初始化它们,那么一切都会很好(只要确保线程在请求属性值时仍然活着)。如果您所说的“只读属性”是指TThread派生类将是唯一更改它们的对象,您需要确保主线程在更改它们时不会读取它们(除非它们是原子值,如整数)。

完美的答案!正是我需要的信息。我正在从TThread派生类内部更新值,但并非所有值都是原子性的。感谢您的回答。 - MrMahgu
1
即使像整数这样的“原子”值也可能失败,如果您的代码没有32位对齐。 - Lieven Keersmaekers
Indy在Core\IdThreadSafe.pas中包含一些原子数据类型,包括IdThreadSafeInt64甚至TIdThreadSafeBoolean。 - mjn
2
仅仅更新"a.s.a.p."是不够的。在安全的情况下,基本上只有一种方法可以做到这一点 - 当执行初始化的方法在主线程的上下文中执行时,即在构造函数中。一旦多个线程可以访问字段,它就不再安全。 - mghie
@mghie:非常正确,我应该在那里更加具体。作为一种替代方法,您可以使用TThread中的“createSuspended”,并在继续它之前从主线程触发一些初始化。不是很好,但我在某些情况下看到过这种情况。 - Paul-Jan
@Lieven:出于兴趣,您在哪种情况下的 Delphi 属性不是 32 位对齐的?我们是指记录(紧凑或关闭对齐)吗? - Paul-Jan

3
基本类型如IntegerBooleanCharPointer可以随时安全读取。引用类型,如string、接口和动态数组,只有在没有其他线程同时分配新值的情况下才能安全读取。例如,使用关键部分或Synchronized方法来确保主线程读取时线程不会修改值。
您还需要记住,在您使用之前,任何值都可能已经过时 - 线程可能在您读取它和使用它之间写入了一个新值。

我相信它被称为“同步”(末尾没有D)。 - Mason Wheeler

2
这取决于属性类型,可能还取决于它们的访问器方法。
type
  TMyThread = class(TThread)
  private
    FIntfield: integer;
  public
    property IntField: integer read FIntField;
  end;

访问此属性不会有问题,因为访问32位值是原子操作。但如果属性大于32位或类引用可能在主线程访问时更改,则会遇到问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接