
Se supone que el siguiente programa en C ilustra la condición de carrera entre procesos secundarios y primarios:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
fork();
printf("\n 1234567890 \n");
return 0;
}
Cuando mis amigos lo ejecutan (enubuntu), obtienen el resultado esperado, que está mezclado 1234567890s
Un ejemplo :12312345645678907890
Pero cuando pruebo el mismo programa en miArco Linux, nunca da tal resultado. Siempre es uno tras otro.
1234567890
1234567890
Me gusta esoarco linuxEs de alguna manera evitar la condición de carrera, pero me gustaríadesactivarcualquiera de estas características y me gustaría obtener resultados como los de mi amigo.
Respuesta1
La printf
llamada ejecutaría una o más write(2)
llamadas al sistema y el orden en que se procesan sería el orden real de la salida. Uno o más, porque depende del almacenamiento en búfer dentro de la biblioteca C. Con la salida almacenada en el búfer de línea (yendo a la terminal), probablemente recibirá dos write
llamadas, una para la nueva línea inicial y otra para el resto.
write(1, "\n", 1);
write(1, " 1234567890 \n", 13);
Es posible programar otro proceso entre las llamadas, dando primero las dos líneas vacías y luego las líneas con los dígitos, pero dado que no hay mucho procesamiento en marcha, es poco probable que ocurra en un sistema descargado.
Tenga en cuenta que, dado que ambos procesos imprimen exactamente lo mismo, no importa cuál va primero, siempre y cuando uno no interrumpa al otro.
Si la salida va a un archivo o una tubería, el valor predeterminado es que esté completamente almacenado en el búfer, por lo que probablemente solo recibirá una write
llamada (por proceso) y no habrá posibilidad de resultados mixtos.
Su ejemplo de dígitos entremezclados sería posible si los dígitos se emitieran uno por uno, con llamadas individuales al sistema. Es difícil entender por qué una implementación de biblioteca sensata haría eso al imprimir una cadena estática cuya longitud se conoce. Con más escrituras en un bucle, sería más probable que se produzcan resultados entremezclados:
Algo como esto:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int i;
setbuf(stdout, NULL); /* explicitly unbuffered */
int x = fork();
for (i = 0 ; i < 500 ; i++) {
printf("%d", !!x);
}
if (x) {
wait(NULL);
printf("\n");
}
return 0;
}
Me da un resultado como el siguiente. La mayoría de las veces es así, no siempre. Depende del sistema decidir cómo programar los procesos. La imprevisibilidad es la razón por la que normalmente intentamos evitar las condiciones de carrera.
111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111
111100000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000010000001001100
110000000011001100110011000000010011001100110000000100110011001100000001001
100110011000000010011001100110000000100110011001100000001001100110011000000
...
Respuesta2
Mi sospecha es que la fork()
llamada al sistema está reteniendo al proceso principal o secundario el tiempo suficiente para permitir que el otro proceso finalice la llamada printf()
y la cadena aparezca en la salida incluso antes de llegar a la suya printf()
.
Generar una gran cantidad de cadenas en un bucle probablemente mostrará la salida entremezclada que usted describe, si tanto el proceso principal como el secundario tienen tiempo para ejecutar los bucles simultáneamente.
"Solucionar" esto probablemente implicaría reescribir la fork()
llamada al sistema o los componentes del kernel involucrados en ella.