2010-06-02 4 views
5

Tenga en cuenta la situación siguiente. Tenemos una función de C++ con una variable local estática:¿Cómo abordar la seguridad de subprocesos de los datos de servicio utilizados para mantener variables locales estáticas en C++?

void function() 
{ 
    static int variable = obtain(); 
    //blahblablah 
} 

la función tiene que ser llamado desde varios subprocesos Al mismo tiempo, por lo que añadir una sección crítica para evitar el acceso simultáneo a nivel local estática:

void functionThreadSafe() 
{ 
    CriticalSectionLockClass lock(criticalSection); 
    static int variable = obtain(); 
    //blahblablah 
} 

pero ¿será esto suficiente? Quiero decir que hay algo mágico que hace que la variable se inicialice no más de una vez. Así que hay algunos datos de servicio mantenidos por el tiempo de ejecución que indican si cada local estática ya se ha inicializado.

¿La sección crítica del código anterior también protege los datos del servicio? ¿Se requiere protección adicional para este escenario?

+0

En cuanto a 'gcc' ha habido esta respuesta: http://stackoverflow.com/questions/1270927/are-function-static-variables-thread-safe-in-gcc –

Respuesta

5

C++ dice que su variable estática solo se debe inicializar una vez; sin embargo, C++ no se ocupa de los hilos (aún).

gcc (al menos en los sistemas * nix) hace la magia adecuada para proteger de forma segura varios hilos inicializando una variable estática. De acuerdo con http://social.msdn.microsoft.com/Forums/en/vcgeneral/thread/12f8e2c7-d94d-4904-8c79-a0b0d1088e0b, msvc no lo hace, y en ese caso tendrá que bloquear la inicialización usted mismo.

Guardar la inicialización con una sección crítica debe proteger todo esto - es decir, su functionThreadSafe() está bien - (a menos obtain() llamadas en sí functionThreadSafe()

http://blogs.msdn.com/b/oldnewthing/archive/2004/03/08/85901.aspx es digno de una lectura en este sentido

En lo personal, a. evite las sorpresas. Intentaré reescribir esto para que pueda inicializar variable usted mismo, una vez, antes de crear cualquier subproceso, por ejemplo,

static int variable = 0; 
void init_variable() //call this once, at the start of main() 
{ 
    variable = obtain(); 
} 

void function() 
{ 
    //use variable, lock if you write to it 
} 
0

Para evitar el bloqueo en cualquier caso, se puede ir con esto:

void functionThreadSafe() 
{ 
    static int *variable = 0; 
    if (variable == 0) 
    { 
     CriticalSectionLockClass lock(criticalSection); 
     // Double check for initialization in different thread 
     if (variable == 0) 
     { 
      variable = new int(obtain()); 
     } 
    } 
    //blahblablah 
} 
+0

Ahora tiene otro local estático. ¿Qué cambió en comparación con el código en cuestión? – sharptooth

+0

No necesita bloquear en cada llamada a la función. – jopa

+0

Eso es genial, pero no aborda la seguridad de subprocesos de los datos de servicio utilizados para mantener el local estático. – sharptooth

0

Algunos esquiva laterales puede probar que podría resolver su problema de fondo:

  • usted podría hacer int variable haber una thread-local static, si los diferentes subprocesos realmente no necesitan compartir el valor de esta variable ni pasar datos entre sí a través de ella.
  • en un int en x86, puede utilizar una lectura/escritura atómica como por InterlockedCompareExchange() o su equivalente en su plataforma. Esto permite que múltiples hilos accedan de forma segura a la variable sin bloqueos. Sin embargo, solo funciona para tipos atómicos nativos del hardware (por ejemplo, palabras de 32 bits y de 64 bits). También tendrá que averiguar qué hacer si dos hilos desean escribir en la variable al mismo tiempo (es decir, uno descubrirá que el otro le ha escrito cuando realiza la operación compare-and-swap).
1

(tengo publicar esto en otra pregunta, pero también es una respuesta a éste)

Aquí es mi opinión (si realmente no se puede inicializar antes de que se ponen en marcha las discusiones):

que he visto (y utilizado) algo como esto para proteger la inicialización estática, utilizando impulso :: vez

#include <boost/thread/once.hpp> 

boost::once_flag flag; 

// get thingy 
const Thingy & get() 
{ 
    static Thingy thingy; 

    return thingy; 
} 

// create function 
void create() 
{ 
    get(); 
} 

void use() 
{ 
    // Ensure only one thread get to create first before all other 
    boost::call_once(&create, flag); 

    // get a constructed thingy 
    const Thingy & thingy = get(); 

    // use it 
    thingy.etc..()   
} 

en mi entendimiento, de esta manera todas las discusiones esperar en impulso :: call_once exc ept uno que creará la variable estática. Se creará solo una vez y luego nunca se volverá a llamar. Y luego ya no tienes ningún candado.

Cuestiones relacionadas