2011-06-22 35 views
7

我有其在多個線程共享單例類。爲了防止多重訪問問題,我在訪問類的一個或另一個屬性時使用Lock方法。問題是可以改進代碼並將Lock方法放入單例類中,而不是每次在代碼中訪問類屬性時都放入它。Singleton類中的多線程應用程序,鎖定建議

/* Class code*/ 
    public class ServerStatus 
    { 


     private static ServerStatus _instance; 
     public static ServerStatus Instance 
     { 
      get { return _instance ?? (_instance = new ServerStatus()); } 
      set { _instance = value; } 
     } 

     ServerStatus() 
     { 
      PistonCount = 0; 
      PistonQueue = new List<string>(); 
      ErrorList = new List<string>(); 
     } 




     public int PistonCount { get; set; } 

     public List<string> PistonQueue { get; set; } 

     public List<string> ErrorList { get; set; } 
    } 



/*Code for accessing class properties*/ 
private static readonly object Locker = new object();  
/*Skip*/ 

lock (Locker) 
{ 
ServerStatus.Instance.PistonQueue.Add(e.FullPath); 
} 
    /*Skip*/ 

lock (Locker) 
{ 
    ServerStatus.Instance.PistonCount++; 
} 

回答

4

ServerStatus自身也要保持同步,這一類的不是外部客戶。話雖如此,你需要重構ServerStatus並創建一些線程安全(帶鎖定)方法:

刪除這些屬性:public List<string> PistonQueue { get; set; }因爲即使您可以鎖定這些屬性,您也無法控制哪些客戶端一旦他們掌握了實際的PistonQueue

...與方法,如更換(對不起僞代碼,我也懶得去思考今天):

public PistonQueueAdd(string fullPath) 
{ 
    lock(_serverStatusSyncRoot) 
    { 
     // ... 
    } 
} 
+0

+1這就是我也終於向他暗示,但你描述得更好! – Dummy01

3

這是單線程安全模式我的情況下,使用您有興趣:

public class DataAccess 
{ 
    #region Singleton 

    private static readonly object m_SyncRoot = new Object(); 

    private static volatile DataAccess m_SingleInstance; 

    public static DataAccess Instance 
    { 
     get 
     { 
      if (m_SingleInstance == null) 
      { 
       lock (m_SyncRoot) 
       { 
        if (m_SingleInstance == null) 
         m_SingleInstance = new DataAccess(); 
       } 
      } 

      return m_SingleInstance; 
     } 
    } 

    private DataAccess() 
    { 
    } 

    #endregion 
} 
+0

如果這是有效使用中,第一件事就是去除可怕'm_'前綴。 –

+1

你的回答不回答我的問題。我問如何減少代碼中的Lock方法,並將Lock放入類中來鎖定屬性。 – Tomas

+3

@ Mr.Disappointment你在那裏做的非常重要的筆記!恭喜!現在回到問題及其答案,你有什麼有用的建議給問這個問題的人嗎? – Dummy01

2

恕我直言,這是the definitive solution在一個單身線程安全鎖。從它(名單第五):

public sealed class Singleton 
{ 
    private Singleton() 
    { 
    } 

    public static Singleton Instance { get { return Nested.instance; } } 

    private class Nested 
    { 
     // Explicit static constructor to tell C# compiler 
     // not to mark type as beforefieldinit 
     static Nested() 
     { 
     } 

     internal static readonly Singleton instance = new Singleton(); 
    } 
} 
+0

+1我看了這個解決方案一段時間了,並且正在尋找作爲回答發佈。這是最好的解決方案,我猜想,沒有鎖,並不會創建實例,直到你需要它 –

+0

你的答案不回答我的問題。我問如何減少代碼中的Lock方法,並將Lock放入類中來鎖定屬性。您將展示如何鎖定新的實例初始化。 – Tomas

+0

@Tomas:如果以這種方式設置屬性,則不需要顯式鎖定。這是關鍵的一點。 – Yuck

0

這是相當普遍的。在getters/setters中鎖定/解鎖更安全(不能忘記這麼做),並且更方便(鎖使用該屬性時無需直接訪問),而不是每個屬性訪問的外部鎖。

RGDS, 馬丁

+0

但是,從我發佈的鏈接來看,確實如此:「不幸的是,由於每次請求實例都會獲取鎖,所以性能會受到影響。」 – Yuck

+0

...順便說一句,我沒有倒下你。我其實不認爲你寫的是值得贊成的。 – Yuck

+0

另外,我不會說這是最好的實踐 - 應該以最小的方式獲得鎖,無論是在執行方面還是在範圍方面 - 必須獲得並釋放對想要使線程安全的類的每個屬性的鎖效率低下,難以維護。 –