2014-06-05 29 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