我有一个对象x,需要从多个(5个以上线程)访问。对象的结构是
Tx = class
private
Fx: integer;
public
property x: integer read Fx read Fx;
etc;
什么是更好(最优雅)的保护方式:
一种)
Tx = class
private
Fx: integer;
public
property x: integer read Fx read Fx;
public
constructor Create; <--- Create the criticalsection here
destructor Destroy; <--destroy it here
etc;
var
cs: TCriticalSection;
Obj: Tx;
function GetSafeObject(): Tx;
begin
CS.Enter;
try
Result:= Obj;
finally
CS.Leave;
结尾;
并始终以GetSafeObj()。x:= 3的形式访问该对象;
或者
Tx = class
private
Fx: integer;
FCS: TCriticalSection;
public
property x: integer read GerX read SetX;
public
constructor Create; <--- Create the criticalsection here
destructor Destroy; <--destroy it here
etc;
where
function Tx.Getx(): integer;
begin
CS.Enter;
try
Result:= Fx;
finally
CS.Leave;
end;
end;
结尾;
并始终正常访问该对象。我猜第一个选择更优雅,即使这两种方法都可以正常工作。意见?
最佳答案
选择选项B,将关键部分置于对象的内部。如果该类的用户必须使用外部函数安全地访问该实例,那么不可避免的是有人不会这样做并且房屋将折叠。
您还需要考虑要保护多种并行读取和写入操作的语义。如果在getter和setter中放入锁,则可以保证对象在内部是一致的,但是对象的用户可能会看到多线程工件。例如,如果线程A将10写入对象的属性,线程B将50写入同一对象的属性,则其中只有一个可以倒数第二个。如果A恰好排在最前面,则A将观察到他们给该属性写了一个10,但是当他们再次读回该属性时,他们看到B的50在A的写后读之间的间隙中潜入其中。
还要注意,您实际上并不需要锁来保护单个整数字段。对齐的指针大小的整数写入是当今几乎所有硬件系统上的原子操作。您绝对需要一个锁来保护诸如结构之类的多段数据或诸如同时更改两个相关字段之类的多步骤操作。
如果有任何方法可以重新设计,以使这些对象位于线程上的特定操作本地,请执行此操作。制作数据的本地副本可能会稍微增加您的内存占用量,但是与在整个应用程序中保留互斥地雷相比,它可以大大简化多线程代码,并且运行速度更快。还要寻找其他简化的假设-如果您可以设置系统以使该对象在多个线程都可用时是不可变的,则该对象根本不需要任何锁定保护。只读数据非常适合在线程之间共享。非常非常好。
关于multithreading - Delphi:使用关键部分的首选保护方式,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8101711/