2014-06-05 28 views
1

有两个对象实例,我应该从两个并发线程,从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例如两个“选项”的树节点>>

  1. 点击(如我通过TMaster实例访问从属对象) 。当发生这种情况时,我发送一个调用master.CMD_GET_SLAVE的UDP数据包,在这种方法中,我从FrBuffer读取答案并写入slave.statusByte。

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

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

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

回答

4

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

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

在此特定示例中,跨多个线程访问从站不是问题。真正的问题是udpsend()。您正面临着两个线程同时发送请求,然后读取对方的响应的风险。取决于UDP协议的性质,这可能会或可能不会导致问题。

如果是这样,您可能需要将UDP通信移至其自己的专用线程。当你需要发送一个请求时,你可以把它放在一个线程看的线程安全队列中,以及有关响应到达时如何处理的信息(把它分配给一个slave,调用一个回调函数,signal等待的事件等)。线程可以接收排队的请求并发送它。当响应返回时,它可以相应地进行委托。然后CMD_GET_SLAVE()将阻止其调用线程等待该响应到达。这将有助于避免任何重叠。

+0

谢谢。你告诉访问相同的对象/字段在这里不是问题。那是因为我没有从'statusByte'上的线程做任何计算,只是写它,所以它的'原子'? 关于udpsend,以及我想只是为了TIdUDPClient的另一个实例,但那是浪费资源。你提到的队列,在实践中看到类似的东西会很高兴。 – grinner