2012-03-23 9 views
5

Tengo algunas preguntas sobre el uso de bloqueo para proteger mi estructura de datos compartidos. Estoy usando C/C++/ObjC/ObjC++Multithreading: ¿necesito proteger mi variable en el método de solo lectura?

Por ejemplo, tengo una clase de contador que usan en el entorno multi-hilo

class MyCounter { 
private: 
    int counter; 
    std::mutex m; 

public: 
    int getCount() const { 
     return counter; 
    } 
    void increase() { 
     std::lock_guard<std::mutex> lk(m); 
     counter++; 
    } 
}; 
  1. ¿Es necesario utilizar std::lock_guard<std::mutex> lk(m); en getCount() método para hacerlo ¿a salvo de amenazas?

  2. ¿Qué sucede si solo hay dos hilos: un hilo de lectura y un hilo de escritor entonces, ¿tengo que protegerlo? Como solo hay un hilo modificando la variable, creo que no ocurrirá ninguna actualización perdida.

  3. Si hay varios escritor/lector para una variable de tipo primitiva compartida (por ejemplo, int) ¿qué desastre puede ocurrir si solo bloqueo el método de escritura pero no el método de lectura? ¿El tipo de 8bits marcará la diferencia en comparación con el tipo de 64 bits?

  4. ¿Hay algún tipo primitivo que sea atómico por defecto? Por ejemplo, escribir en un char es siempre atómico? (Sé que esto es cierto en Java, pero no sé de C++ y estoy usando el compilador LLVM en Mac si las cosas plataforma)

+1

"C/C++/ObjC/ObjC++" Estos son todos los idiomas completamente diferentes. Elegir uno; parece que eligió C++. – GManNickG

+0

Estoy usando ObjC para GUI y C++ para backend y ObjC++ para combinarlos. También ObjC++ es superconjunto de otros. Escojo C++ como ejemplo. –

+0

Eso es bueno, pero no los combine en una lista como uno solo. :) Solo di que estás interesado en una respuesta en cuatro idiomas diferentes. – GManNickG

Respuesta

7

Sí, a menos que se puede garantizar que los cambios en la variable subyacente counter son atómicas, necesitas el mutex

ejemplo

clásico, dicen counter es un valor de dos bytes que se incrementa en etapas (no-atómicas):

add 1 to lower byte 
if lower byte is 0: 
    add 1 to upper byte 

y el valor inicial es 255.

Si otro hilo viene en cualquier lugar entre el cambio de byte inferior y el cambio de byte superior, leerá 0 en lugar del 255 correcto (preincremento) o 256 (incremento posterior).

En términos de qué tipos de datos son atómicos, el último estándar de C++ los define en el encabezado <atomic>.

Si no tiene tienen capacidades C++ 11, entonces depende de la implementación qué tipos son atómicos.

+0

¿Estaba pensando que estamos usando una CPU de 32/64 bits que debería actualizar una variable de tamaño de 32 bits a la vez sin dividirla en dos pasos? –

+0

@ xlc0212, la palabra operativa allí es "debería". Por supuesto, si puede verificar eso, puede estar bien. Pero no se trata simplemente de una cuestión de subprocesos en una CPU, es posible que esté utilizando varias CPU, interrupciones y todo tipo de cosas maravillosas que suceden debajo de las cubiertas. – paxdiablo

+0

@ xlc0212 que no funcionará (confiable/predeciblemente); lo que tienes es consistencia secuencial, no consistencia estricta. lo que observa si el tratamiento secuencial como estricto será "cercano, pero no del todo", y el programa solo tendrá errores desagradables. – justin

3

Sí, también necesitaría bloquear la lectura en este caso.

Existen varias alternativas: una cerradura es bastante pesada aquí. Las operaciones atómicas son las más obvias (sin bloqueo). También hay otros enfoques para bloquear este diseño: el bloqueo de lectura y escritura es un ejemplo.

+1

+1, pero solo como una nota: no se garantiza que los tipos 'std :: atomic' en C++ estén libres de bloqueo. Lo más probable es que estén libres de bloqueos para enteros en la mayoría de las plataformas, pero no es una garantía explícita (sin embargo, puede verificarlo). – KillianDS

+0

@KillianDS gracias - buen punto. – justin

1

Sí, creo que también es necesario bloquear la lectura. Pero dado que está utilizando las características de C++ 11, ¿por qué no usa std::atomic<int> counter;?

+0

eso es otro problema: '#error no está implementado'. Esto sucedió si trato de '#include ' –

0

No puede garantizar que múltiples hilos no modifiquen su variable al mismo tiempo. y si tal situación ocurre, su variable se distorsionará o el programa podría bloquearse. Para evitar tales casos, siempre es mejor y más seguro hacer que el programa sea seguro.

Puede utilizar las técnicas estadísticas de sincronización disponibles como: mutex, Lock, atributo de sincronización (disponible para MS C++)

+0

. Él realmente garantizó que varios hilos no pueden escribir al mismo tiempo. Todavía no es correcto omitir un bloqueo de lectura, pero por otros motivos (publicado en otras respuestas). – KillianDS

+0

¿Cómo puede estar tan seguro en una situación de múltiples hilos sin usar la sincronización? –

+0

'increase' (el único método no const) utiliza sincronización, y los datos compartidos son' private' – MSalters

Cuestiones relacionadas