2010-06-18 15 views
5

que tienen la clase siguienteSingleton y multi-threading

class Singleton 
{ 
    private: 

    static Singleton *p_inst; 
    Singleton(); 

    public: 

    static Singleton * instance() 
    { 
     if (!p_inst) 
     { 
     p_inst = new Singleton(); 
     } 

     return p_inst; 
    } 
}; 

por favor haga elaborada sobre las precauciones tomadas mientras que la aplicación Singleton en el entorno multi-hilo.

+0

al pegar el código, asegúrese de utilizar espacios en lugar de pestañas, ya que este último daña la marca. – ChrisF

+2

Marque aquí: http://stackoverflow.com/questions/1008019/c-singleton-design-pattern/1008289#1008289 –

+4

El precauciones que tomaría es no aplicar un producto único. Siempre son más problemas de lo que valen. –

Respuesta

7

En multi-threading que la cláusula

if(!p_inst) 
{ 
    p_inst = new Singleton(); 
} 

es en realidad 3 acciones separadas. Obtiene el valor de p_inst, estableciendo el valor de p_inst y escribiendo el valor de p_inst. Así que get-set-write significa que debe poner un candado alrededor de p_inst; de lo contrario, puede tener 2 hilos que crean un valor Singleton que usa cada subproceso.

Aquí es como se puede ver el problema, asumir que su Singleton tiene un campo mutable val:

thread A -> p_inst is NULL 
    thread B -> p_inst is NULL 
     thread A -> set to Singleton (1) 
      thread B -> set to Singleton (2) 
       thread C -> p_inst is Singleton (2) 
        thread A -> set val to 4 
         thread B -> set val to 6 
         thread C -> get val (it's 6) 
          thread A -> get val (it's 4!!) 

Ves? Hay 2 copias de un Singleton flotando, ninguna de las cuales sabe sobre la otra. El tercer hilo que verifica en el Singleton solo verá la última asignación. Pero con el bloqueo, puede evitar asignaciones múltiples y este tipo de problemas.

+0

¿Es algo como eso? instancia de Singleton * estática() { if (! P_inst) { Mutex m; m.lock(); // Sección crítica if (! P_inst) p_inst = new Singleton(); // Finalizar la sección crítica m.unlock(); } return p_inst; } – ronan

+0

Entiendo que al usar mutex y lock se convierte en un patrón de diseño lento, pero ¿hay alguna forma de optimizarlo? – ronan

+3

@ronan: Sí, no use este antipatrón que es "singleton". – ereOn

5

Usted tendrá que utilizar un mutex y bloquear el puntero antes de asignar o leerlo, haciendo de este un patrón de diseño lenta (y imo simplemente terrible).

+0

+1: Mis pensamientos, exactamente. – ereOn

1

Para construcción multiproceso, utilice la variable estática en una función de instancia(). La inicialización de las variables estáticas está automáticamente protegida por el compilador. Cualquier otra operación requiere bloqueo explícito. Use mutexes

class Singleton 
{ 
    private: 

    Singleton(); 

    public: 

    static Singleton * instance() 
    { 
     static Singleton inst; 
     return &inst; 
    } 
}; 
+0

Tengo que entender ¿Puedo usar la palabra clave volátil? ¿Cómo ayuda? – ronan

+4

No existen garantías del estándar anterior a C++ 0x de que la inicialización de variables estáticas dentro de un método esté protegida de las condiciones de carrera. Ciertos compiladores de C++ pueden hacer esto seguro, pero muchos no lo hacen. – rjnilsson

+0

Esto es INCORRECTO pre-C++ 0x. Otro comentarista ya hizo alusión a esto, pero voy a ser explícito al respecto. – mike

1

Deberías preguntarte a qué te refieres con hilo de seguridad.

  • ¿Su Singleton necesita realmente la seguridad hilo?

    Si no, considere un enfoque hilo-estática

  • ¿Quieres garantizar que no hay dos instancias del singleton nunca se crean?

    Si no, su solución anterior es probablemente muy bien, sin ningún tipo de bloqueo: usted tiene una condición de carrera en la construcción - pero no les importa ya que finalmente sólo uno será sobrevivir - sin embargo, es posible que tenga una fuga de recursos a menos que tenga cuidado, lo que puede o no ser significativo. (Esto es esencialmente un caché).

  • ¿Quieres garantizar que a la larga sólo una instancia queda?

  • ¿Le importan los costos de bloqueo?

    Si no es así (que es bastante común), sólo puede poner un candado alrededor de ella y ser feliz.

Un Singleton es un patrón que puede hacer frente a diversos problemas - pero ¿qué sabor de hilo de seguridad que se requiere poco tiene que ver con el propio patrón singleton y mucho que ver con lo que usted quiere para.

+0

- Gracias por la explicación. Tendré que conocer el enfoque de Thread estático aquí, básicamente quiero que Singleton sea seguro para hilos. – ronan

4

seré breve: depende de su compilador.

  • Si su compilador implementa la sincronización de subprocesos múltiples para la estática local (es decir, instancias estáticas integradas en un método), utilícela y finalícela.
  • Si no, Herb Sutter demostró que era imposible.

Ahora, debes darte cuenta de que no es necesario.

Hay 2 maneras de lidiar con esto, que no requieren ningún conocimiento multi-hilo.

  1. Simplemente utilice una instancia static en lugar de asignarla dinámicamente. Seguro y simple. Puede causar problema con el fin de inicialización si necesita acceder a él desde otro static variables
  2. Crear la instancia singleton antes de tener más de un hilo. El truco habitual es llamarlo desde main.

Por supuesto, la verdadera pregunta es: ¿no se puede simplemente pasar una referencia al objeto en lugar de crear una variable global? Sería más fácil hacer la prueba;)

4

puede eliminar todos los problemas mediante la simple asignación (de la forma que elija) dichos objetos antes de iniciar varios subprocesos. Esto no siempre es posible debido a restricciones de diseño (utilizando los singletons en estática, NECESITA asignación diferida, etc.), pero es simple y le da el control de la secuencia de creación. A veces, rastrear problemas con respecto al orden y el tiempo de asignación de dichos objetos es una molestia que puede evitar fácilmente.

P.S. - Sé que esto no responde directamente a su pregunta, pero puede ser una solución práctica a un problema real sin complejidad.