Processo pai sempre imprimindo saída após filho

0

Considere o seguinte código em execução no Solaris 11.3:

int main(void) {
    pid_t pid = fork();
    if (pid > 0) {
        printf("[%ld]: Writing from parent process\n", getpid());
    }
    if (pid == 0) {
        execl("/usr/bin/cat", "/usr/bin/cat", "file.c", (char *) 0);
        perror("exec failed");
        exit(1);
    }
 }

Sempre que eu executo, a linha "Writing from parent" é sempre a última. Eu não ficaria surpreso com esse resultado se a tarefa da minha escola não fosse usar espera (2) para imprimir essa linha somente depois que o processo filho tiver terminado. Por que isso acontece e como garantir que essa linha seja impressa antes do processo filho ser executado (ou a ordem é pelo menos indefinida), então posso usar com segurança wait (2) ou waitpid (2) para resolver isso?

    
por Dmitry Serov 09.03.2016 / 18:21

2 respostas

2

Como @AndrewHenle comentou, dependendo do sistema para agendar seus processos em uma sequência específica, é inseguro e injustificado. Mesmo quando o agendamento parece ser consistente (como no seu caso), não há nada que impeça os implementadores do sistema operacional de alterar o comportamento do agendador.

Se a ordem de operações entre processos / threads for relevante, alguma forma de comunicação é necessária.

Para o seu cenário, uma simples leitura de bloqueio pode fazer o trabalho. Crie um tubo antes do garfo. Em seguida, escreva para o pipe do pai apenas depois que o pai tiver imprimido sua mensagem. Enquanto isso, a tentativa da criança de ler do canal bloqueará sua execução até que o pai escreva.

Negligenciando a manipulação de erros e os descritores de arquivos de pipe não utilizados em cada processo (que geralmente são explicitamente fechados após o bifurcação):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/wait.h>

int main(void) {

    char buf[1];
    int pipe_fds[2];
    pipe(pipe_fds);

    pid_t pid = fork();
    if (pid > 0) {
        printf("[%ld]: Writing from parent process\n", getpid());
        write(pipe_fds[1], "_", 1);
        wait(NULL);
    }
    if (pid == 0) {
        read (pipe_fds[0], buf, 1);
        execl("/usr/bin/cat", "/usr/bin/cat", "file.c", (char *) 0);
        perror("exec failed");
        exit(1);
    }

Você provavelmente deve usar wait no pai, de modo que, se for executado a partir de um terminal, a saída do filho e o prompt do shell não serão intercalados.

    
por 09.03.2016 / 21:48
0

Considere isso do ponto de vista do kernel: ele apenas varreu todos os tipos de caches configurando o processo filho, e a próxima execução provavelmente reutiliza parte do novo conteúdo do cache. Enquanto isso, o pai pode ser agendado em outra CPU.

    
por 09.03.2016 / 23:21