88 votos

He escuchado i++ no es seguro para subprocesos, es ++i thread-safe?

He oído que i++ no es un hilo de seguridad declaración ya que en la asamblea se reduzca a almacenar el valor original como temporales, en algún lugar, en incrementos y, a continuación, sustituya, el cual podría ser interrumpido por un cambio de contexto.

Sin embargo, me pregunto acerca++. Como lo que yo puedo decir, esto se reduciría a un único conjunto de instrucciones, tales como 'add r1, r1, 1' y ya que es tan sólo una instrucción, que sería ininterrumpible por un cambio de contexto.

¿Alguien puede aclarar? Estoy asumiendo que una plataforma x86 se utiliza.

154voto

paxdiablo Puntos 341644

Has oído mal. Bien puede ser que "i++" es seguro para subprocesos para un compilador específico y específicos de la arquitectura del procesador, pero no se contemplan en las normas a todos. De hecho, desde el multi-threading no es parte de la ISO en C o C++ estándares (a), no se puede considerar la posibilidad de que algo sea thread-safe basado en lo que usted piensa que va a compilar.

Es muy factible que ++i podría compilar una secuencia arbitraria, tales como:

load r0,[i]  ; load memory into reg 0
incr r0      ; increment reg 0
stor [i],r0  ; store reg 0 back to memory

que no sería seguro para subprocesos en mi (imaginario) de la CPU que no tiene memoria de incremento instrucciones. O puede ser inteligente y se compila en:

lock         ; disable task switching (interrupts)
load r0,[i]  ; load memory into reg 0
incr r0      ; increment reg 0
stor [i],r0  ; store reg 0 back to memory
unlock       ; enable task switching (interrupts)

donde lock deshabilita unlock permite interrupciones. Pero, incluso entonces, esto puede no ser seguro para subprocesos en una arquitectura que ha más de uno de estos CPUs de intercambio de memoria ( lock sólo puede deshabilitar las interrupciones para una CPU).

El lenguaje en sí mismo (o bibliotecas para él, si es que no se construye en el lenguaje) proporcionará hilo de seguridad de las construcciones y se debe utilizar esas en lugar de depender de su entendimiento (o, posiblemente, el malentendido) de lo que la máquina código será generado.

Cosas como Java synchronized y pthread_mutex_lock() (disponible para C/C++ en algunos sistemas operativos) son lo que usted necesita para buscar en (a).


(a) Esta pregunta se la hicieron antes de que el C++11 se completó. Que la iteración de la norma ha introducido roscado de apoyo en la especificación del lenguaje, incluyendo la exclusión mutua semáforos similar a la de los hilos POSIX y operaciones atómicas.

42voto

Jim Mischel Puntos 68586

Usted no puede hacer una declaración general acerca de cualquiera ++i o i++. ¿Por qué? Considere la posibilidad de incrementar un entero de 64 bits en un sistema de 32 bits. A menos que el subyacente de la máquina tiene un quad palabra "carga, el incremento de la tienda" la instrucción, el incremento de valor que va a necesitar varias instrucciones, cualquiera de los cuales puede ser interrumpido por un hilo de cambio de contexto.

Además, ++i no siempre "agregar uno para el valor." En un lenguaje como C, incrementar un puntero en realidad, agrega el tamaño de la cosa señaló. Es decir, si i es un puntero a un 32 bytes de la estructura, ++i añade 32 bytes. Mientras que casi todas las plataformas tienen un "valor de incremento en la dirección de memoria" de la instrucción que es atómica, no todos tienen un atómica "agregar valor arbitrario para el valor en la dirección de memoria" en la instrucción.

14voto

yogman Puntos 2091

Ambos son de hilo de seguros.

Una CPU puede hacer matemáticas directamente con la memoria. Lo hace indirectamente por cargar el valor de la memoria y de hacer los cálculos con los registros de la CPU.

i++

register int a1, a2;

a1 = *(&i) ; // One cpu instruction: LOAD from memory location identified by i;
a2 = a1;
a1 += 1; 
*(&i) = a1; 
return a2; // 4 cpu instructions

++i

register int a1;

a1 = *(&i) ; 
a1 += 1; 
*(&i) = a1; 
return a1; // 3 cpu instructions

Para ambos casos, hay una condición que resulta en el unpreditable i valor.

Por ejemplo, supongamos que hay dos simultáneas ++i subprocesos con el uso de cada registro a1, b1, respectivamente. Y, con el cambio de contexto ejecutado como el siguiente:

register int a1, b1;

a1 = *(&i);
a1 += 1;
b1 = *(&i);
b1 += 1;
*(&i) = a1;
*(&i) = b1;

En consecuencia, yo no se convierte en i+2, se convierte en i+1, lo cual es incorrecto.

Para remediar esto, moden Cpu proporcionan algún tipo de BLOQUEO, DESBLOQUEO de las instrucciones de la cpu durante el intervalo de un cambio de contexto es deshabilitado.

En Win32, uso InterlockedIncrement() para hacer i++ para el hilo de seguridad. Es mucho más rápido que depender de la exclusión mutua.

11voto

Eclipse Puntos 27662

Si está compartiendo incluso un int a través de los subprocesos en un entorno de múltiples núcleos, que tiene necesidad de barreras de memoria en su lugar. Esto puede significar el uso de enclavamiento instrucciones (ver InterlockedIncrement en win32, por ejemplo), o el uso de una lengua (o compilador) que hace que ciertos subprocesos garantías. Con CPU de nivel de instrucción de reordenación y cachés y otros temas, a menos que usted tenga esas garantías, no asume nada compartido a través de los subprocesos es seguro.

Edit: Una cosa que usted puede asumir con la mayoría de las arquitecturas es que si se trata de un alineados correctamente palabras sueltas, no terminar con una sola palabra, que contienen una combinación de los dos valores que se puré juntos. Si dos escribe ocurren a lo largo de la parte superior de uno al otro, uno va a ganar, y los otros serán descartados. Si usted tiene cuidado, usted puede tomar ventaja de esto, y ver que tanto ++i o i++ son thread-safe en el único escritor/lector de múltiples situación.

8voto

Max Lybbert Puntos 11822

Si desea atómica incremento en C++ se puede utilizar C++0x bibliotecas ( std::atomic de tipo de datos) o algo por el estilo TBB.

Hubo una vez un tiempo en el que la GNU directrices de codificación dijo que la actualización de los tipos de datos que caben en una sola palabra fue "generalmente son seguras", pero que es un consejo equivocado para máquinas SMP, mal para algunas arquitecturas, y el mal cuando se utiliza un compilador de optimización.


Para aclarar la "actualización de una palabra de tipo de datos" comentario:

Es posible que dos CPUs en una máquina SMP para escribir a la misma ubicación de memoria en el mismo ciclo, y, a continuación, tratar de propagar el cambio a la otra Cpu y la memoria caché. Incluso si sólo una palabra de datos que se escriben por lo que el escribe sólo tomar un ciclo completo, que también ocurren simultáneamente, por lo que no puede garantizar que escribir correctamente. Usted no obtendrá parcialmente los datos actualizados, pero una escritura va a desaparecer porque no hay otra manera de manejar este caso.

Comparación e intercambio correctamente las coordenadas entre varias CPUs, pero no hay ninguna razón para creer que cada una de las variables de asignación de tipos de datos word utilizará comparación e intercambio.

Y mientras que un compilador de optimización no afecta a cómo un load/store es compilado, se puede cambiar cuando la carga/tienda sucede, causando graves problemas si usted espera que sus lecturas y escrituras a suceder en el mismo orden en que aparecen en el código fuente (la más famosa de las cuales es doble control de bloqueo no funciona en vainilla C++).

NOTA original de Mi respuesta también dijo que Intel de 64 bits de la arquitectura se había roto en el trato con los 64 bits de datos. Eso no es cierto, lo he editado la respuesta, pero mi edición afirmó chips PowerPC estaban rotos. Que es true cuando la lectura inmediata de los valores (es decir, constantes) en registros (ver las dos secciones de la denominada "Carga de los punteros" en virtud de listado 2 y el listado 4) . Pero no es una instrucción para la carga de datos desde la memoria en un ciclo (lmw), así que me he quitado esa parte de mi respuesta.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X