Класс Singleton в многопоточном приложении, предложение блокировки - PullRequest
7 голосов
/ 22 июня 2011

У меня есть одноэлементный класс, который разделен на несколько потоков.Чтобы предотвратить проблемы множественного доступа, я использую метод Lock при доступе к тому или иному свойству класса.Вопрос состоит в том, можно ли улучшить код и поместить метод Lock в одноэлементный класс, а не помещать его каждый раз, когда свойство кода доступно в коде?

/* 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 ]

4 голосов
/ 22 июня 2011

ServerStatus должен поддерживать собственную синхронизацию, а не внешние клиенты этого класса. При этом вам необходимо провести рефакторинг ServerStatus и создать несколько поточно-ориентированных (с блокировкой) методов:

Удалите эти свойства: public List<string> PistonQueue { get; set; }, поскольку даже если вы можете заблокировать эти свойства, вы не сможете контролировать действия клиентов, когда они получат фактический PistonQueue.

... и заменить такими методами, как (извините, псевдокод, я не могу думать сегодня):

public PistonQueueAdd(string fullPath)
{
    lock(_serverStatusSyncRoot)
    {
        // ...
    }
}
3 голосов
/ 22 июня 2011

Это шаблон синглтоновых потоков, который я использую на случай, если вы заинтересованы:

    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
}
2 голосов
/ 22 июня 2011

ИМХО, это окончательное решение для поточно-ориентированной блокировки в синглтоне.Из него (пятое в списке):

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 голосов
/ 22 июня 2011

Это довольно часто. Блокировка / разблокировка в получателях / установщиках намного безопаснее (вы не можете забыть сделать это) и более удобна (блокировка не должна быть доступна напрямую везде, где вы используете свойство), чем внешняя блокировка при каждом доступе к свойству .

Rgds, Martin

...