variable usar son qué programacion métodos metodos metodo los estáticos estaticos estatico entre diferencia cuando clase atributos atributo c# multithreading singleton

usar - ¿Es seguro el subproceso estático de C#?



static programacion (10)

Aquí está la versión de Cliffnotes de la página de MSDN anterior en c # singleton:

Usa el siguiente patrón, siempre, no te puedes equivocar:

public sealed class Singleton { private static readonly Singleton instance = new Singleton(); private Singleton(){} public static Singleton Instance { get { return instance; } } }

Más allá de las características obvias de singleton, te ofrece estas dos cosas de forma gratuita (con respecto a singleton en c ++):

  1. construcción perezosa (o ninguna construcción si nunca fue llamada)
  2. sincronización

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


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

La inicialización de tipo por sí sola no creará un interbloqueo a menos que algún código llamado desde un inicializador de tipo (directa o indirectamente) invoque explícitamente las operaciones de bloqueo.

El siguiente código da como resultado un punto muerto

using System.Threading; class MyClass { static void Main() { /* Won’t run... the static constructor deadlocks */ } static MyClass() { Thread thread = new Thread(arg => { }); thread.Start(); thread.Join(); } }

El autor original es Igor Ostrovsky, vea su post here .


El constructor estático terminará de ejecutarse antes de que cualquier subproceso pueda acceder a la clase.

private class InitializerTest { static private int _x; static public string Status() { return "_x = " + _x; } static InitializerTest() { System.Diagnostics.Debug.WriteLine("InitializerTest() starting."); _x = 1; Thread.Sleep(3000); _x = 2; System.Diagnostics.Debug.WriteLine("InitializerTest() finished."); } } private void ClassInitializerInThread() { System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.GetHashCode() + ": ClassInitializerInThread() starting."); string status = InitializerTest.Status(); System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.GetHashCode() + ": ClassInitializerInThread() status = " + status); } private void classInitializerButton_Click(object sender, EventArgs e) { new Thread(ClassInitializerInThread).Start(); new Thread(ClassInitializerInThread).Start(); new Thread(ClassInitializerInThread).Start(); }

El código de arriba produjo los resultados a continuación.

10: ClassInitializerInThread() starting. 11: ClassInitializerInThread() starting. 12: ClassInitializerInThread() starting. InitializerTest() starting. InitializerTest() finished. 11: ClassInitializerInThread() status = _x = 2 The thread 0x2650 has exited with code 0 (0x0). 10: ClassInitializerInThread() status = _x = 2 The thread 0x1f50 has exited with code 0 (0x0). 12: ClassInitializerInThread() status = _x = 2 The thread 0x73c has exited with code 0 (0x0).

Aunque el constructor estático tardó mucho tiempo en ejecutarse, los otros subprocesos se detuvieron y esperaron. Todos los subprocesos leen el valor de _x establecido en la parte inferior del constructor estático.


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.) Por lo tanto, a menos que tenga alguna IL extraña perdida llamando a Singleton :: .cctor directamente (improbable) 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 Instancia es segura para subprocesos.

Tenga en cuenta que si el constructor de Singleton accede a la propiedad Instancia (incluso de manera indirecta), la propiedad Instancia será nula. Lo mejor que puede hacer es detectar cuándo sucede esto y lanzar una excepción, al verificar que la instancia no sea nula en el acceso a la propiedad. Después de que su constructor estático complete, la propiedad Instancia no será nula.

Como la respuesta de Zoomba señala, deberá hacer que Singleton sea seguro para acceder desde múltiples hilos, o implementar un mecanismo de bloqueo utilizando la instancia de Singleton.



Se garantiza que los constructores estáticos se activarán solo una vez por cada dominio de aplicación, por lo que su enfoque debería estar bien. Sin embargo, funcionalmente no es diferente de la versión en línea más concisa:

private static readonly Singleton instance = new Singleton();

La seguridad de subprocesos es más un problema cuando estás inicializando las cosas con pereza.


Se garantiza que los constructores estáticos se ejecutarán solo una vez por dominio de aplicación, antes de que se creen las instancias de una clase o se acceda a los miembros estáticos. http://msdn.microsoft.com/en-us/library/aa645612.aspx

La implementación que se muestra es segura para subprocesos para la construcción inicial, es decir, no se requiere bloqueo o prueba 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 abajo.

public class Singleton { private static Singleton instance; // Added a static mutex for synchronising use of instance. private static System.Threading.Mutex mutex; private Singleton() { } static Singleton() { instance = new Singleton(); mutex = new System.Threading.Mutex(); } public static Singleton Acquire() { mutex.WaitOne(); return instance; } // Each call to Acquire() requires a call to Release() public static void Release() { mutex.ReleaseMutex(); } }


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.

class MyObject<T> { static MyObject() { //this code will get executed for each T. } }

EDITAR:

Aquí está la demostración:

static void Main(string[] args) { var obj = new Foo<object>(); var obj2 = new Foo<string>(); } public class Foo<T> { static Foo() { System.Diagnostics.Debug.WriteLine(String.Format("Hit {0}", typeof(T).ToString())); } }

En la consola:

Hit System.Object Hit System.String


Solo para ser pedante, pero no existe un constructor estático, sino inicializadores de tipo estático, aquí hay una pequeña demostración de la dependencia del constructor estático cíclico que ilustra este punto.


Usar un constructor estático en realidad es seguro para hilos. El constructor estático está garantizado para ejecutarse solo una vez.

De la especificación de lenguaje C # http://msdn.microsoft.com/en-us/library/aa645612(VS.71).aspx :

El constructor estático para una clase se ejecuta como máximo una vez en un dominio de aplicación dado. La ejecución de un constructor estático es activada por el primero de los siguientes eventos que ocurren dentro de un dominio de aplicación:

  • Se crea una instancia de la clase.
  • Se hace referencia a cualquiera de los miembros estáticos de la clase.

Así que sí, puedes confiar en que tu singleton será correctamente instanciado.

Zooba hizo un punto excelente (¡y 15 segundos antes que yo, también!) De que el constructor estático no garantizará un acceso compartido seguro al subproceso. Eso tendrá que ser manejado de otra manera.