2010-05-13 63 views
3

我想設計一個類,我有訪問一些嵌套字段的問題,我有一些關於多線程如何安全整個設計的問題。我想知道是否任何人有更好的想法應該如何設計或者應該做出什麼改變?C#多線程安全類設計

using System; 
using System.Collections; 

namespace SystemClass 
{ 
public class Program 
{ 
    static void Main(string[] args) 
    { 
     System system = new System(); 

     //Seems like an awkward way to access all the members 
     dynamic deviceInstance = (((DeviceType)((DeviceGroup)system.deviceGroups[0]).deviceTypes[0]).deviceInstances[0]); 
     Boolean checkLocked = deviceInstance.locked; 

     //Seems like this method for accessing fields might have problems with multithreading 
     foreach (DeviceGroup dg in system.deviceGroups) 
     { 
      foreach (DeviceType dt in dg.deviceTypes) 
      { 
       foreach (dynamic di in dt.deviceInstances) 
       { 
        checkLocked = di.locked; 
       } 
      } 
     } 
    } 
} 

public class System 
{ 
    public ArrayList deviceGroups = new ArrayList(); 

    public System() 
    { 
     //API called to get names of all the DeviceGroups 
     deviceGroups.Add(new DeviceGroup("Motherboard")); 
    } 
} 

public class DeviceGroup 
{ 
    public ArrayList deviceTypes = new ArrayList(); 

    public DeviceGroup() {} 

    public DeviceGroup(string deviceGroupName) 
    { 
     //API called to get names of all the Devicetypes 
     deviceTypes.Add(new DeviceType("Keyboard")); 
     deviceTypes.Add(new DeviceType("Mouse")); 
    } 
} 

public class DeviceType 
{ 
    public ArrayList deviceInstances = new ArrayList(); 
    public bool deviceConnected; 

    public DeviceType() {} 

    public DeviceType(string DeviceType) 
    { 
     //API called to get hardwareIDs of all the device instances 
     deviceInstances.Add(new Mouse("0001")); 
     deviceInstances.Add(new Keyboard("0003")); 
     deviceInstances.Add(new Keyboard("0004")); 

     //Start thread CheckConnection that updates deviceConnected periodically 
    } 

    public void CheckConnection() 
    { 
     //API call to check connection and returns true 
     this.deviceConnected = true; 
    } 
} 

public class Keyboard 
{ 
    public string hardwareAddress; 
    public bool keypress; 
    public bool deviceConnected; 

    public Keyboard() {} 

    public Keyboard(string hardwareAddress) 
    { 
     this.hardwareAddress = hardwareAddress; 
     //Start thread to update deviceConnected periodically 
    } 

    public void CheckKeyPress() 
    { 
     //if API returns true 
     this.keypress = true; 
    } 
} 

public class Mouse 
{ 
    public string hardwareAddress; 
    public bool click; 

    public Mouse() {} 

    public Mouse(string hardwareAddress) 
    { 
     this.hardwareAddress = hardwareAddress; 
    } 

    public void CheckClick() 
    { 
     //if API returns true 
     this.click = true; 
    } 
} 

}

回答

2

使類線程安全是一件很難的事情做一個赫克。

許多人傾向於嘗試的第一種天真的方式就是添加一個鎖並確保沒有使用可鎖定數據的代碼不使用鎖。因此,我的意思是班級中可能發生變化的所有內容都必須在觸摸數據之前首先鎖定鎖定對象,無論是從中讀取數據還是寫入數據。但是,如果這是你的解決方案,那麼你應該對代碼不做任何事情,只是記錄類不是線程安全的,並將其留給使用它的程序員。

爲什麼?

因爲您已經有效地將所有訪問權限序列化了。兩個嘗試同時使用該類的線程,即使它們正在觸摸它的單獨部分,也會阻塞。其中一個線程將被授予訪問權限,另一個將等待第一個線程完成。

這實際上不鼓勵您的類的多線程用法,所以在這種情況下,您將增加鎖定到您的類的開銷,而實際上並沒有從中獲得任何好處。是的,你的班級現在是「線程安全」的,但它實際上並不是一個好的線程 - 公民。

另一種方式是開始添加粒度鎖,或者編寫無鎖構造(嚴重困難),以便如果對象的兩個部分不總是相關的,則訪問每個部分的代碼都有自己的鎖。這將允許訪問數據不同部分的多個線程並行運行而不會彼此阻塞。

無論你需要一次處理多個數據的哪一部分,這都會變得很困難,因爲你需要非常小心地按照正確的順序進行鎖定,否則會遇到死鎖。班級的責任應該是確保按照正確的順序進行鎖定,而不是使用班級的代碼。

至於你的具體例子,它在我看來好像將從後臺線程改變的部分只是「是設備連接」布爾值。在這種情況下,我會讓該字段變成易變的,並在每個字段周圍使用鎖。但是,如果設備列表將從後臺線程更改,那麼您將遇到問題很快。

你應該首先嚐試識別將被後臺線程改變的所有部件,然後設計情景您希望更改傳播到其他線程,如何對變化做出反應,等