
O programa C a seguir deve ilustrar a condição de corrida entre processos filho e pai:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
fork();
printf("\n 1234567890 \n");
return 0;
}
Quando meus amigos executam (emUbuntu), eles obtêm a saída esperada, que é confusa 1234567890s
Um exemplo :12312345645678907890
Mas quando tento o mesmo programa no meuArco Linux, nunca fornece tal saída. É sempre um após o outro.
1234567890
1234567890
eu gosto dissoarco linuxé de alguma forma evitar a condição de corrida, mas eu gostaria dedesabilitarquaisquer desses recursos e gostaria de obter resultados como os do meu amigo.
Responder1
A printf
chamada executaria uma ou mais write(2)
chamadas de sistema e a ordem em que elas seriam processadas seria a ordem real da saída. Um ou mais, porque depende do buffer dentro da biblioteca C. Com a saída com buffer de linha (indo para o terminal), você provavelmente receberá duas write
chamadas, uma para a nova linha inicial e outra para o restante.
write(1, "\n", 1);
write(1, " 1234567890 \n", 13);
É possível agendar outro processo entre as chamadas, fornecendo primeiro as duas linhas vazias, depois as linhas com os dígitos, mas como não há muito processamento em andamento, é improvável em um sistema descarregado.
Observe que como ambos os processos imprimem exatamente a mesma coisa, não importa qual deles seja executado primeiro, desde que um não interrompa o outro.
Se a saída for para um arquivo ou canal, o padrão é que ela seja totalmente armazenada em buffer, então você provavelmente receberá apenas uma write
chamada (por processo) e nenhuma chance de saída mista.
Seu exemplo de dígitos misturados seria possível se os dígitos fossem gerados um por um, com chamadas de sistema individuais. É difícil entender por que uma implementação de biblioteca sensata faria isso ao imprimir uma string estática cujo comprimento é conhecido. Com mais gravações em loop, a saída misturada seria mais provável:
Algo assim:
#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 dá uma saída como abaixo. Na maioria das vezes, nem sempre. Cabe ao sistema decidir como agendar os processos. A imprevisibilidade é a razão pela qual geralmente tentamos evitar condições de corrida.
111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111
111100000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000010000001001100
110000000011001100110011000000010011001100110000000100110011001100000001001
100110011000000010011001100110000000100110011001100000001001100110011000000
...
Responder2
Minha suspeita é que a fork()
chamada do sistema está atrasando o processo pai ou filho por tempo suficiente para permitir que o outro processo termine a chamada printf()
e faça com que a string apareça na saída antes mesmo de chegar à sua própria printf()
.
A saída de um grande número de strings em um loop provavelmente mostrará a saída misturada que você descreve, se os processos pai e filho tiverem tempo para executar os loops simultaneamente.
"Consertar" isso provavelmente envolveria reescrever a fork()
chamada do sistema ou os componentes do kernel envolvidos nela.