Condição de corrida não funciona no Arch Linux

3

O seguinte programa C deve ilustrar a condição de corrida entre os processos pai e filho:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
     fork();
     printf("\n 1234567890 \n");
     return 0;
}

Quando meus amigos o executam (no Ubuntu ), eles obtêm a saída esperada, que é confusa 1234567890s

Um exemplo: 12312345645678907890

Mas quando eu tento o mesmo programa no meu Arch Linux , ele nunca gera essa saída. É sempre um após o outro.

 1234567890 

 1234567890 

Eu gosto que o arch linux é como evitar condições de corrida, mas eu gostaria de desativar quaisquer desses recursos e gostaria de obter resultados como os de meus amigos.

    
por Severus Tux 22.04.2017 / 21:17

2 respostas

3

A chamada printf executaria uma ou mais chamadas de sistema write(2) , e a ordem em que são 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), é provável que você receba 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 que outro processo seja agendado entre as chamadas, dando primeiro as duas linhas vazias, depois as linhas com os dígitos, mas dado que não há muito processamento acontecendo, é improvável em um sistema descarregado.

Note que, como os dois processos imprimem exatamente a mesma coisa, não importa qual vai primeiro, contanto que um não interrompa o outro.

Se a saída for para um arquivo ou um pipe, o padrão é que ele seja totalmente armazenado em buffer, portanto, você provavelmente obteria apenas uma write call (por processo) e nenhuma chance de saída mista.

Seu exemplo de dígitos misturados seria possível se os dígitos estivessem sendo enviados um a um, com chamadas individuais do sistema. É 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 um loop, a saída misturada seria mais provável:

Algo parecido com isto:

#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á saída como abaixo. Na maioria das vezes isso é, nem sempre. Cabe ao sistema decidir como agendar os processos. A imprevisibilidade é a razão pela qual geralmente tentamos evitar as condições de corrida.

111111111111111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111111111111111111111111
111100000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000010000001001100
110000000011001100110011000000010011001100110000000100110011001100000001001
100110011000000010011001100110000000100110011001100000001001100110011000000
...
    
por 22.04.2017 / 22:36
0

Suspeito que a chamada de sistema fork() esteja atrasando o processo pai ou filho por tempo suficiente para permitir que o outro processo conclua a chamada para printf() e que a sequência apareça na saída antes mesmo de chegar seu próprio printf() .

Produzir 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.

"Corrigindo" isso provavelmente envolveria reescrever a chamada do sistema fork() ou os componentes do kernel envolvidos nela.

    
por 22.04.2017 / 22:14