我应该从两个并发线程,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实例访问从属对象)>>
点击treenode。当发生这种情况时,我发送一个UDP数据包,调用master.CMD_GET_SLAVE,在这个方法中,我从FrBuffer读取答案并编写slave.statusByte。
有一个工作线程循环执行相同的操作(调用master.CMD_GET_SLAVE)。这种情况我不从treenode.data获取slave实例,而是从master的TList对象(FSlaves)获取。
问题是,如何正确管理?因为当用户点击treenode时可能会出现这种情况,同时可能会有来自该线程的传入访问。
我不接触来自工作线程的任何VCL控件,'只是'从两个并发线程访问相同的对象。我是否应该在同步主VCL线程时执行相同的同步(因为刷新了一些可视VCL控件)?
答案 0 :(得分:4)
如果您有多个访问共享对象的线程,并且至少有一个线程修改了该对象,那么您通常需要使用锁(例如TCriticalSection
或TMonitor
)来序列化访问到共享对象。这样做的一些选择:
答案 1 :(得分:3)
在此特定示例中,跨多个线程访问从属服务器不是问题。真正的问题是udpsend()
。您冒着让两个线程同时发送请求然后读取彼此响应的风险。根据UDP协议的性质,可能会也可能不会导致问题。
如果是,您可能需要将UDP通信移动到其自己的专用线程。当您需要发送请求时,您可以将它放在线程查看的线程安全队列中,以及有关响应何时到达的信息(将其分配给从站,调用回调函数,信号)一个等待的事件等)。线程可以获取排队的请求并发送它。当响应返回时,它可以相应地委派它。然后CMD_GET_SLAVE()
将阻止其调用线程等待该响应到达。这有助于避免任何重叠。