Bloqueo de doble verificación en patrón singleton

puede ser una pregunta básica

para tener un singleton en un entorno de subprocesos múltiples, podemos usar un bloqueo. Consulte el fragmento de código. Pero, ¿por qué necesitamos un bloqueo doble verificado en un patrón singleton? Y más, ¿qué significa bloqueo con doble verificación?

class singleton
{
    private static singleton instance = null;
    private static singleton() { }

    private static object objectlock = new object();

    public static singleton Instance
    {
        get
        {

            lock (objectlock) //single - check lock
            {
                if (instance == null)
                {
                    instance = new singleton();
                }

                return instance;
            }
        }

    }
}

preguntado el 10 de mayo de 11 a las 13:05

csharpindepth.com/Articles/General/Singleton.aspx es de hecho todo lo que necesita saber. Estaba a punto de publicar lo mismo cuando otros dos se me adelantaron. Eso debería decir mucho por su valor. -

6 Respuestas

Jon Skeet explica esto en detalle.

Las cerraduras son caras.
Si el objeto ya existe, no tiene sentido abrir un candado.
Por lo tanto, tiene un primer control fuera de la cerradura.

Sin embargo, incluso si el objeto no existía antes de mirar, otro hilo puede haberlo creado entre los if condición y la lock declaración.
Por lo tanto, debe verificar nuevamente el interior de la cerradura.

Sin embargo, la mejor manera de escribir un singleton es usar un static constructor:

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();
    }
} 

contestado el 10 de mayo de 11 a las 17:05

en el enlace dado - // ¡Código incorrecto! ¡No utilice! Tercera versión: intento de seguridad de subprocesos mediante el bloqueo de doble verificación - Raghav55

@ Raghav55: ¿Qué quieres decir? No puedo ver una tercera versión en esta respuesta. - Daniel Hilgarth

@Raghav: Esta no es la tercera versión. ¿Querías comentar sobre la respuesta de @TcKs? - SLaks

lo siento, no proporcioné el enlace: csharpindepth.com/Articles/General/Singleton.aspx - Raghav55

Encontré una razón para no usar esta solución; si ocurre una excepción, su cliente verá la excepción anidada en una TypeInitializationException que la hará menos obvia. Por lo tanto, vuelvo a la solución de bloqueo de verificación doble (solución 3 de Jon Skeet) - Patrick del equipo de NDepend

Y con .Net 4.xy versiones posteriores, debe ceder a la clase Lazy cuando sea posible, ya que este patrón se usa con la opción Inicialización y publicación. (nota: la inversa también está disponible cuando la creación no es segura para subprocesos, pero la publicación de la instancia se realiza a través de la opción Publicación)

Respondido 03 Jul 13, 20:07

Singleton multiproceso: el mejor enfoque para utilizar el bloqueo de doble verificación

public sealed class Singleton
{
   private static volatile Singleton _instance;
   private static readonly object InstanceLoker= new Object();

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         if (_instance == null) 
         {
            lock (InstanceLoker) 
            {
               if (_instance == null) 
                  _instance = new Singleton();
            }
         }

         return _instance;
      }
   }
}

Respondido 16 ago 13, 16:08

La "mejor" forma que conozco es esta:

public class MySingleton {
    // object for synchronization
    private static readonly object syncRoot = new object();
    // the singleton instance
    private static MySingleton @default;

    public static MySingleton Default {
        get {
            // geting singleton instance without locking
            var result = @default;
            // if result is NOT null, no additional action is required
            if ( object.ReferenceEquals(result, null) ){
                // lock the synchronization object
                lock(syncRoot) {
                    // geting singleton instanc in lock - because
                    // the value of @default field could be changed
                    result = @default;

                    // checking for NULL
                    if ( object.ReferenceEquals(result, null) ) {
                        // if result is NULL, create new singleton instance
                        result = new MySingleton();
                        // set the default instance
                        @default = result;
                    }
                }
            }

            // return singleton instance
            return result;
        }
    }
}

Respondido el 29 de diciembre de 17 a las 07:12

Si esta es realmente la mejor manera que conoce, le sugiero que lea el enlace proporcionado. - Daniel Hilgarth

csharpindepth.com/Articles/General/Singleton.aspx. Esto es innecesariamente complicado. - SLaks

@Daniel Hilgarth: Es la misma implementación que la "Tercera versión: intento de seguridad de subprocesos mediante el bloqueo de verificación doble". - TcKs

No; tienes cheques extra. Una vez que esté en la cerradura, no necesita cambiar. Además, recomienda contra la tercera versión. - SLaks

@SLack: hay 2 comprobaciones, como en el enlace. Porque entre "var result = @default;" y "lock (syncRoot)" puede otro hilo inicializar el valor singleton. - TcKs

Si crea el objeto en el inicializador de campo, no necesita el bloqueo:

class singleton
{
    private static singleton instance = new singleton();
    private static singleton() { }

    public static singleton Instance
    {
        get { return instance; }
    }
}

Además, tenga en cuenta que el bloqueo solo controla la creación del objeto, el objeto aún debería ser seguro para subprocesos si lo está utilizando en varios subprocesos.

contestado el 10 de mayo de 11 a las 17:05

Cuando intentamos ejecutar el método de la clase singleton usando bibliotecas Parallel. No reconoce el comportamiento de singleton debido a que el subproceso múltiple se está ejecutando en TPL, lo que provoca la falla del concepto Singleton Pattern. Para superar este problema existe el concepto de bloqueo del objeto para que a la vez solo un subproceso pueda acceder a él. Pero este no es un enfoque eficiente porque la participación de la verificación de cerraduras crea relojes innecesarios al objeto. Para evitarlo utilizamos "Comprobación de doble bloqueo"

enter image description here

Respondido el 17 de Septiembre de 17 a las 11:09

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.