2009-04-07 10 views
9

Estoy buscando utilizar un singleton en un servicio Win multiproceso para hacer el registro y quería saber cuáles son algunos de los problemas que podría encontrar. Ya configuré la instancia get para administrar la sincronización con¿Cuáles son los peligros de utilizar un Singleton en una aplicación de subprocesos múltiples

private static volatile Logging _instance; 
    private static object _syncRoot = new object(); 

    private Logging(){} 
    public static Logging Instance 
    { 
     get 
     { 
      if (_instance==null) 
      { 
       lock(_syncRoot) 
       { 
        if (_instance == null) 
        { 
         _instance = new Logging(); 
        } 
       } 
      } 
      return _instance; 
     } 
    } 

¿Hay alguna otra cosa de la que deba preocuparme?

+1

¡Aquí hay dragones! Corre mientras puedas. – Samuel

+1

"No te metas en los asuntos del dragón; para usted es crujiente y sabe bien con ketchup. " –

Respuesta

13

Eso se ve bastante bien para mí.

Consulte Implementing the Singleton Pattern in C# para obtener más información.

Editar: Sin embargo, probablemente debería poner la devolución dentro de la cerradura.

+1

+1 para un buen enlace –

+0

y bloqueo antes de comparar instancia a nulo. –

+0

@Joel ¿En serio? No había pensado en eso ... –

0

Creo que si los métodos de instancia de registro son seguros para subprocesos, no hay de qué preocuparse.

3

Los Singleton tienen el potencial de convertirse en un cuello de botella para acceder al recurso incorporado por la clase, y forzar el acceso secuencial a un recurso que de otro modo podría usarse en paralelo.

En este caso, eso puede no ser algo malo, porque no quiere que varios elementos escriban en su archivo en el mismo instante, y aún así no creo que su implementación tenga ese resultado. Pero es algo de lo que debes estar consciente.

+0

Prefiero que sea un cuello de botella y luego se cuelgue, que es lo que estaba sucediendo cuando tenía mucha actividad, esa es la razón por la que estoy usando un singleton. +1 para una buena idea –

1

Está utilizando double-checked locking lo que se considera un antipatrón. Wikipedia tiene patrones con y sin inicialización diferida para diferentes idiomas.

Después de crear la instancia de singleton, debe asegurarse de que todos los métodos sean seguros para la ejecución de subprocesos.

12

Esto es más informativo que cualquier otra cosa.

Lo que has enviado es el una doble comprobación de bloqueo algoritmo - y lo que has publicado hará el trabajo, por lo que yo soy consciente. (A partir de Java 1.5 también funciona allí). Sin embargo, es muy frágil: si te equivocas un poco, puedes introducir condiciones de carrera muy sutiles.

por lo general prefiero para inicializar el singleton en el inicializador estático: (. Añadir un constructor estático si quieres un poco de pereza adicional)

public class Singleton 
{ 
    private static readonly Singleton instance = new Singleton(); 

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

    private Singleton() 
    { 
     // Do stuff 
    } 
} 

más fácil de esa patrón para hacerlo bien, y en la mayoría de los casos, lo hace igual de bien.

Hay más detalles en mi C# singleton implementation page (también vinculado por Michael).

En cuanto a los peligros, diría que el mayor problema es que se pierde la capacidad de prueba. Probablemente no demasiado malo para el registro.

+0

el enlace a su artículo está roto. –

+0

Eso es bastante triste, ¿no? Tales son los peligros de publicar con un resfriado apestoso. Corregido, gracias por notarlo. –

+0

¿Cuál es el motivo de usar una propiedad aquí? ¿No es lo suficientemente seguro usar el campo público de solo lectura estático? –

1

Una mejor sugerencia sería establecer el registrador en un paso de configuración de un solo subproceso, por lo que está garantizado que estará allí cuando lo necesite. En un servicio de Windows, OnStart es un gran lugar para hacer esto.

Otra opción que tiene es utilizar el método System.Threading.Interlocked.CompareExchange (T%, T, T): T para cambiar. Es menos confuso y está garantizado que funciona.

System.Threading.Interlocked.CompareExchange<Logging>(_instance, null, new Logging()); 
+0

No soy un experto en C# pero espero que esto genere una nueva instancia de registro en cada llamada. La 'nueva parte de Logging()' se ejecuta antes del control atómico dentro de InterlockedCompareExchange. –

+0

Tienes razón. Lo malo que eso realmente sería depende de la semántica del constructor de registro (y de los inicializadores). Sostengo que todavía funciona, y la primera sugerencia es mejor. –

2

es necesario asegurarse de que cada método en el registrador son seguros en forma concurrente, es decir, que no se escriben en estado compartido y sin bloqueo adecuado.

+0

¿No usa un singleton para evitar que se ejecuten al mismo tiempo? Creía que ese era el punto. –

+0

No, los subprocesos múltiples aún pueden acceder a la única instancia de registro. Sus métodos * necesitan * ser seguros para subprocesos. +1 por mencionar esto. – Lucas

+0

@bob: su bloqueo de doble comprobación evita que se cree más de una instancia (para garantizar la individualidad), no impide el acceso simultáneo desde múltiples hilos. – Lucas

Cuestiones relacionadas