2011-06-22 38 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

另外,我不会说这是最好的实践 - 应该以最小的方式获得锁,无论是在执行方面还是在范围方面 - 必须获得并释放对想要使线程安全的类的每个属性的锁效率低下,难以维护。 –