Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/258.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 多线程应用程序中的Singleton类,锁定建议_C#_Class_Locking_Thread Safety - Fatal编程技术网

C# 多线程应用程序中的Singleton类,锁定建议

C# 多线程应用程序中的Singleton类,锁定建议,c#,class,locking,thread-safety,C#,Class,Locking,Thread Safety,我有一个在多个线程中共享的单例类。为了防止多重访问问题,我在访问类的一个或另一个属性时使用Lock方法。问题是,是否有可能改进代码并将锁方法放在singleton类中,而不是每次在代码中访问类属性时都将其放在singleton类中 /* Class code*/ public class ServerStatus { private static ServerStatus _instance; public static ServerStatus

我有一个在多个线程中共享的单例类。为了防止多重访问问题,我在访问类的一个或另一个属性时使用Lock方法。问题是,是否有可能改进代码并将锁方法放在singleton类中,而不是每次在代码中访问类属性时都将其放在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++;
}
/*类代码*/
公共类服务器状态
{
私有静态服务器状态\u实例;
公共静态服务器状态实例
{
获取{return}instance??(_instance=newserverstatus());}
设置{u instance=value;}
}
服务器状态()
{
皮斯顿计数=0;
PistonQueue=新列表();
ErrorList=新列表();
}
公共整数PistonCount{get;set;}
公共列表PistonQueue{get;set;}
公共列表错误列表{get;set;}
}
/*用于访问类属性的代码*/
私有静态只读对象锁定器=新对象();
/*跳过*/
锁(储物柜)
{
ServerStatus.Instance.PistonQueue.Add(e.FullPath);
}
/*跳过*/
锁(储物柜)
{
ServerStatus.Instance.PistonCount++;
}

这是我在您感兴趣时使用的单例线程安全模式:

    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
}
IMHO,这是针对单例中的线程安全锁定。从中(排名第五):


这是相当普遍的。在getter/setter中锁定/解锁比在每个属性访问上使用外部锁更安全(您不能忘记这样做),也更方便(在使用属性的任何地方都不必直接访问该锁)

Rgds,
Martin

服务器状态
应保持其自身的同步,而不是此类的外部客户端。也就是说,您需要重构
ServerStatus
,并创建一些线程安全(带锁定)方法:

删除这些属性:
public List PistonQueue{get;set;}
,因为即使您可以锁定这些属性,但一旦客户机获得实际的
PistonQueue
,您也无法控制它们做什么

…并替换为以下方法(对不起,伪代码,我今天懒得去想):


如果这是积极使用,第一件事是删除可怕的
m
前缀。你的答案没有回答我的问题。我问如何减少代码中的锁方法,并将锁放在类中以锁定属性。@失望先生,这是您在那里做的非常重要的说明!祝贺现在回到问题及其答案,你有什么有用的建议给提问者吗?+1这是确定的单例线程安全初始值设定项,请看,你必须使用
volatile
,并且必须在getter上使用
,你不能再减少了。我想你问的是你的班级在做什么。如果您可以使用一些方法同时维护类属性,那么只需在那里执行锁定,并保持get属性的简单性。但是,如果这不是您想要的,那么很抱歉,除了在属性代码中锁定之外,我看不到任何其他解决方案。但是,从我发布的链接中可以看出,这是正确的:“不幸的是,性能会受到影响,因为每次请求实例时都会获得一个锁定。”…顺便说一句,我没有投您反对票。实际上,我并不认为你写的东西值得否决。而且,我也不会说这是最佳实践——无论是在执行方面还是在作用域方面,都应该以最小的代价获得锁——必须在类的每个属性中获取并释放锁,以使线程安全,这是低效的,而且更难维护。嗯,也许我应该用“取决于二传手/接球手做什么”来限定我的答案。如果他们只是设置/获取成员数据,那么在锁内花费的时间将非常少&同样存在争用的可能性。单个属性读/写的扩展锁定策略的问题是,这通常会变成扩展死锁策略。锁越多,锁策略越复杂,预防问题就越困难,尤其是在持续开发中:每次添加/更改内部功能时,都必须重新检查锁:(+1我看到这个解决方案有一段时间了,一直在寻找答案。我想这是最好的解决方案,没有锁,在需要时才创建实例。你的答案没有回答我的问题。我问如何减少代码中的锁方法,并将锁放在类中以锁定属性。你展示了如何锁定新实例初始化。@Tomas:如果属性是这样设置的,您就不需要显式锁。这就是重点。嗯,很有趣,我会测试它并让您知道。@Uck:您误读了这个问题。当添加到列表或增加计数器时,仍然需要锁。+1这是我最后向他建议的,但您描述得更好!
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();
    }
}
public PistonQueueAdd(string fullPath)
{
    lock(_serverStatusSyncRoot)
    {
        // ...
    }
}