En otras palabras, ¿es seguro este hilo de implementación de Singleton?
public class Singleton
{
private static Singleton instance;
private Singleton() { }
static Singleton()
{
instance = new Singleton();
}
public static Singleton Instance
{
get { return instance; }
}
}
c#
multithreading
singleton
urini
fuente
fuente
Instance
a la vez. Se le indicará a uno de los hilos que primero ejecute el inicializador de tipo (también conocido como el constructor estático). Mientras tanto, todos los otros hilos que quieran leer laInstance
propiedad se bloquearán hasta que el inicializador de tipo haya finalizado. Solo después de que el inicializador de campo haya concluido, se permitirá que los hilos obtengan elInstance
valor. Entonces nadie puede ver elInstance
sernull
.X
terminan siendo-1
incluso sin subprocesos . No es un problema de seguridad de hilos. En cambio, el inicializador sex = -1
ejecuta primero (está en una línea anterior en el código, un número de línea inferior). Luego seX = GetX()
ejecuta el inicializador , lo que hace que las mayúsculas seanX
iguales a-1
. Y luego el constructor estático "explícito", sestatic C() { ... }
ejecuta el inicializador de tipo , que cambia solo en minúsculasx
. Entonces, después de todo eso, elMain
método (oOther
método) puede continuar y leer mayúsculasX
. Su valor será-1
, incluso con un solo hilo.Respuestas:
Se garantiza que los constructores estáticos se ejecuten solo una vez por dominio de aplicación, antes de que se creen instancias de una clase o se acceda a cualquier miembro estático. https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors
La implementación que se muestra es segura para subprocesos para la construcción inicial, es decir, no se requiere ninguna prueba de bloqueo o nula para construir el objeto Singleton. Sin embargo, esto no significa que cualquier uso de la instancia se sincronizará. Hay una variedad de formas en que esto se puede hacer; He mostrado uno a continuación.
fuente
Lazy<T>
: cualquiera que use el código que publiqué originalmente lo está haciendo mal (y, sinceramente, no era tan bueno para empezar, hace 5 años, yo no era tan bueno en estas cosas como en la actualidad) -me es :)).Si bien todas estas respuestas dan la misma respuesta general, hay una advertencia.
Recuerde que todas las derivaciones potenciales de una clase genérica se compilan como tipos individuales. Por lo tanto, tenga cuidado al implementar constructores estáticos para tipos genéricos.
EDITAR:
Aquí está la demostración:
En la consola:
fuente
Usar un constructor estático en realidad es seguro para subprocesos. El constructor estático está garantizado para ejecutarse solo una vez.
De la especificación del lenguaje C # :
Entonces, sí, puede confiar en que su singleton se instanciará correctamente.
Zooba hizo un excelente comentario (¡y 15 segundos antes que yo también!) De que el constructor estático no garantizará un acceso compartido seguro para subprocesos al singleton. Eso tendrá que ser manejado de otra manera.
fuente
Aquí está la versión Cliffnotes de la página MSDN anterior en c # singleton:
Utilice el siguiente patrón, siempre, no puede salir mal:
Más allá de las características obvias de singleton, le ofrece estas dos cosas de forma gratuita (con respecto a singleton en c ++):
fuente
Se garantiza que los constructores estáticos se dispararán solo una vez por dominio de aplicación, por lo que su enfoque debería ser correcto. Sin embargo, funcionalmente no es diferente de la versión en línea más concisa:
La seguridad de subprocesos es más un problema cuando está inicializando cosas perezosamente.
fuente
El constructor estático terminará de ejecutarse antes de que cualquier hilo pueda acceder a la clase.
El código anterior produjo los resultados a continuación.
Aunque el constructor estático tardó mucho en ejecutarse, los otros subprocesos se detuvieron y esperaron. Todos los hilos leen el valor de _x establecido en la parte inferior del constructor estático.
fuente
La especificación de Common Language Infrastructure garantiza que "un inicializador de tipo se ejecutará exactamente una vez para cualquier tipo dado, a menos que el código de usuario lo llame explícitamente". (Sección 9.5.3.1.) Entonces, a menos que tenga un poco de IL en la llamada suelta Singleton ::. Cctor directamente (poco probable) su constructor estático se ejecutará exactamente una vez antes de que se use el tipo Singleton, solo se creará una instancia de Singleton, y su propiedad de instancia es segura para subprocesos.
Tenga en cuenta que si el constructor de Singleton accede a la propiedad Instancia (incluso indirectamente), la propiedad Instancia será nula. Lo mejor que puede hacer es detectar cuándo sucede esto y lanzar una excepción, verificando que esa instancia no sea nula en el descriptor de acceso a la propiedad. Después de que su constructor estático se complete, la propiedad Instancia no será nula.
Como señala la respuesta de Zoomba, deberá hacer que Singleton sea seguro para acceder desde múltiples subprocesos, o implementar un mecanismo de bloqueo utilizando la instancia de singleton.
fuente
Solo para ser pedante, pero no existe un constructor estático, sino más bien inicializadores de tipo estático, aquí hay una pequeña demostración de la dependencia cíclica del constructor estático que ilustra este punto.
fuente
El constructor estático garantiza la seguridad de los hilos. Además, consulte la discusión sobre Singleton en DeveloperZen: http://web.archive.org/web/20160404231134/http://www.developerzen.com/2007/07/15/whats-wrong-with-this-code -1-discusión /
fuente
Aunque otras respuestas son en su mayoría correctas, hay otra advertencia con los constructores estáticos.
Según la sección II.10.5.3.3 Razas y puntos muertos de la infraestructura de lenguaje común ECMA-335
El siguiente código da como resultado un punto muerto
El autor original es Igor Ostrovsky, vea su publicación aquí .
fuente