从并发线程访问同一对象

时间:2014-06-05 14:21:45

标签: multithreading delphi object

我应该从两个并发线程,VCL线程和工作线程中访问两个对象实例。

TSlave = class
  ...
public
  ...
  statusByte: byte;
  ...
end;

TMaster = class
private
  FSlaves: TList;
  FrBuffer: array of byte;  
  ...
public
  CMD_GET_SLAVE( aSlave: TSlave );
  ...
end;

procedure TMaster.CMD_GET_SLAVE( aSlave: TSlave );
begin
  ...
  rBuffer := udpsend(); //calling a function that sends udp packet and returns the answer
  aSlave.statusByte := rBuffer[2];
  ...
end;

我将从属对象的引用存储在VCL TTreeNodes的“数据”字段中--treenode.data(我也将它们存储在TMaster私有列表中)。

有两个“选项”用于访问从属对象(编写slave.statusByte)和TMaster实例(因为我通过TMaster实例访问从属对象)>>

  1. 点击treenode。当发生这种情况时,我发送一个UDP数据包,调用master.CMD_GET_SLAVE,在这个方法中,我从FrBuffer读取答案并编写slave.statusByte。

  2. 有一个工作线程循环执行相同的操作(调用master.CMD_GET_SLAVE)。这种情况我不从treenode.data获取slave实例,而是从master的TList对象(FSlaves)获取。

  3. 问题是,如何正确管理?因为当用户点击treenode时可能会出现这种情况,同时可能会有来自该线程的传入访问。

    我不接触来自工作线程的任何VCL控件,'只是'从两个并发线程访问相同的对象。我是否应该在同步主VCL线程时执行相同的同步(因为刷新了一些可视VCL控件)?

2 个答案:

答案 0 :(得分:4)

如果您有多个访问共享对象的线程,并且至少有一个线程修改了该对象,那么您通常需要使用锁(例如TCriticalSectionTMonitor)来序列化访问到共享对象。这样做的一些选择:

  1. 使用锁定外部保护对共享对象的所有访问。
  2. 使用自己的私有锁使对象自我同步。这是内部同步选项。
  3. 选项2对于调用者来说更简单,但强制该类的所有使用者支付同步成本。另一种方法是使对象没有内部同步,然后在其周围包装一个呈现线程安全版本的同步类。

答案 1 :(得分:3)

在此特定示例中,跨多个线程访问从属服务器不是问题。真正的问题是udpsend()。您冒着让两个线程同时发送请求然后读取彼此响应的风险。根据UDP协议的性质,可能会也可能不会导致问题。

如果是,您可能需要将UDP通信移动到其自己的专用线程。当您需要发送请求时,您可以将它放在线程查看的线程安全队列中,以及有关响应何时到达的信息(将其分配给从站,调用回调函数,信号)一个等待的事件等)。线程可以获取排队的请求并发送它。当响应返回时,它可以相应地委派它。然后CMD_GET_SLAVE()将阻止其调用线程等待该响应到达。这有助于避免任何重叠。