Pregunta

Tengo dos hilos, uno actualizando un int y otro leyéndolo.Este es un valor estadístico donde el orden de las lecturas y escrituras es irrelevante.

Mi pregunta es, ¿necesito sincronizar el acceso a este valor multibyte de todos modos?O, dicho de otra manera, parte de la escritura puede completarse y ser interrumpida, y luego ocurre la lectura.

Por ejemplo, piense en un valor = 0x0000FFFF que obtiene un valor incrementado de 0x00010000.

¿Hay algún momento en el que el valor parezca 0x0001FFFF por el que debería preocuparme?Ciertamente, cuanto más grande sea el tipo, más posibilidades habrá de que suceda algo como esto.

Siempre he sincronizado este tipo de accesos, pero tenía curiosidad por saber qué piensa la comunidad.

¿Fue útil?

Solución

Al principio, uno podría pensar que las lecturas y escrituras del tamaño de la máquina nativa son atómicas, pero hay una serie de cuestiones que abordar, incluida la coherencia de la caché entre procesadores/núcleos.Utilice operaciones atómicas como Interlocked* en Windows y su equivalente en Linux.C++ 0x tendrá una plantilla "atómica" para envolverlos en una interfaz agradable y multiplataforma.Por ahora, si está utilizando una capa de abstracción de plataforma, puede proporcionar estas funciones. AS Sí, consulte la plantilla de clase. ACE_Atomic_Op.

Otros consejos

Chico, que pregunta.La respuesta a la cual es:

Sí, no, mmm, bueno, depende.

Todo se reduce a la arquitectura del sistema.En un IA32, una dirección correctamente alineada será una operación atómica.Las escrituras no alineadas pueden ser atómicas, depende del sistema de almacenamiento en caché que se utilice.Si la memoria se encuentra dentro de una única línea de caché L1, entonces es atómica; de lo contrario, no lo es.El ancho del bus entre la CPU y la RAM puede afectar la naturaleza atómica:una escritura de 16 bits correctamente alineada en un 8086 era atómica, mientras que la misma escritura en un 8088 no lo era porque el 8088 solo tenía un bus de 8 bits mientras que el 8086 tenía un bus de 16 bits.

Además, si está utilizando C/C++, no olvide marcar el valor compartido como volátil; de lo contrario, el optimizador pensará que la variable nunca se actualiza en uno de sus subprocesos.

SI está leyendo/escribiendo un valor de 4 bytes Y está alineado con DWORD en la memoria Y está ejecutando la arquitectura I32, ENTONCES las lecturas y escrituras son atómicas.

Sí, necesitas sincronizar los accesos.En C++ 0x será una carrera de datos y un comportamiento indefinido.Con los subprocesos POSIX, ya es un comportamiento indefinido.

En la práctica, es posible que obtenga valores incorrectos si el tipo de datos es mayor que el tamaño de la palabra nativa.Además, es posible que otro hilo nunca vea el valor escrito debido a optimizaciones que mueven la lectura y/o escritura.

Debe sincronizar, pero en determinadas arquitecturas existen formas eficientes de hacerlo.

Lo mejor es utilizar subrutinas (quizás enmascaradas detrás de macros) para poder reemplazar condicionalmente implementaciones con implementaciones específicas de la plataforma.

El kernel de Linux ya tiene parte de este código.

En Windows, se garantiza que Interlocked***Exchange***Add será atómico.

Para hacernos eco de lo que todos dijeron arriba, el lenguaje anterior a C++ 0x no puede garantizar nada sobre el acceso a la memoria compartida desde múltiples subprocesos.Cualquier garantía dependería del compilador.

¡Definitivamente NO!Esa respuesta de nuestra máxima autoridad en C++, M.Aumentar:
No se garantiza que las operaciones con variables "ordinarias" sean atómicas.

No, no lo son (o al menos no puedes asumir que lo son).Dicho esto, existen algunos trucos para hacer esto de forma atómica, pero normalmente no son portátiles (consulte Comparar e intercambiar).

Estoy de acuerdo con muchos y especialmente jason.En Windows, probablemente se usaría InterlockedAdd y sus amigos.

Aparte del problema de caché mencionado anteriormente...

Si transfiere el código a un procesador con un tamaño de registro más pequeño, ya no será atómico.

En mi opinión, los problemas de subprocesos son demasiado complicados para arriesgarse.

Tomemos este ejemplo

int x;
x++;
x=x+5;

Se supone que la primera declaración es atómica porque se traduce en una única directiva de ensamblaje INC que requiere un solo ciclo de CPU.Sin embargo, la segunda asignación requiere varias operaciones, por lo que claramente no es una operación atómica.

Otro, por ejemplo,

x=5;

Nuevamente, debes desmontar el código para ver qué sucede exactamente aquí.

TC, creo que en el momento en que usa una constante (como 6), la instrucción no se completará en un ciclo de máquina.Intente ver el conjunto de instrucciones de x+=6 en comparación con x++

Algunas personas piensan que ++c es atómico, pero estén atentos al ensamblaje generado.Por ejemplo con 'gcc -S':

movl    cpt.1586(%rip), %eax
addl    $1, %eax
movl    %eax, cpt.1586(%rip)

Para incrementar un int, el compilador primero lo carga en un registro y lo almacena nuevamente en la memoria.Esto no es atómico.

La única forma portátil es utilizar el tipo sig_atomic_t definido en el encabezado signal.h para su compilador.En la mayoría de las implementaciones de C y C++, se trata de un int.Luego declara tu variable como "volatile sig_atomic_t".

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top