LINUX.ORG.RU

Запуск программы и ожидание завершения дочерних процессов

 


0

1

Привет!

Есть задача запустить программу и дождаться ее выполнения. С первого взгляда это просто:

system("./p1.elf");

Вот только программа p1 (к исходникам которой нет доступа) вызывает другой процесс, уводя его, судя по всему в фон (&).

Описать программами можно примерно так: Мой программа:

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

int main(void) {
    system("./p1.elf");
    printf("p1 exited\n");
    sleep(5);
    return 0;
}
Эмуляция кода программы p1:
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    system("./p2.elf &");
    return 0;
}
Эмуляция кода программы p2:
#include <stdio.h>
#include <unistd.h>

int main(void) {
    sleep(3);
    printf("report created\n");
    return 0;
}

При запуске, соответственно, будет следующий геморрой:

$ gcc main.c -o main.elf && gcc p1.c -o p1.elf && gcc p2.c -o p2.elf
$ ./main.elf 
p1 exited
report created

Зачем мне это нужно - p2 формирует отчет, который мне нужно прочитать. Я жду завершения работы, чтобы взять отчет из файла. Сейчас стоит костыль - я жду обновления файла после выхода p1. Но файл может не обновиться или я буду ждать слишком долго в случае если p1 завершилась без отчета.

Как мне в main.c дождаться выполнения всех дочерних процессов?

★★★★★

Во первых тебе нужен execve (вместо system), а также fork и wait4. По ключевым словам надеюсь разберёшься.

beastie ★★★★★
()

Я жду завершения работы, чтобы взять отчет из файла.

You are doing it wrong! Посмотри в сторону inotify. И тебе не нужен C, достаточно скрипта на шелле.

DELIRIUM ☆☆☆☆☆
()
Ответ на: комментарий от beastie

Я пробовал работать с wait, но это все равно не поможет, так как p1 запускает p2 демонизированным, отвязанным на /bin/upstart:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

int main(void) {

    char *newargv[] = { NULL };
    char *newenviron[] = { NULL };

    printf("MAIN: My pid is %d, my daddy is %d\n", getpid(), getppid());

    int pid = fork();
    if (pid == 0) {
        // child
        execve("./p1.elf", newargv, newenviron); 
    } else {
        // main
        int status;    
        wait(&status);
    }

    printf("p1 exited\n");
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main(void) {
    printf("P1: My pid is %d, my daddy is %d\n", getpid(), getppid());
    system("./p2.elf &");
    return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main(void) {
    printf("P2: My pid is %d, my daddy is %d\n", getpid(), getppid());
    sleep(3);
    printf("Report created\n");
    return 0;
}
$ gcc main.c -o main.elf && gcc p1.c -o p1.elf && gcc p2.c -o p2.elf
$ ./main.elf 
MAIN: My pid is 12169, my daddy is 6673
P1: My pid is 12170, my daddy is 12169
p1 exited
P2: My pid is 12172, my daddy is 1311
$ Report created
$ ps aux | grep 1311
alex      1311  0.0  0.0  47652  4544 ?        Ss   09:56   0:00 /sbin/upstart --user
PPP328 ★★★★★
() автор топика

child subreaper?

anonymous
()

думал рассказать про то как это легко и приятно делается с pthreads, но что-то передумал. прочитай целиком какой-нибудь букварь для начала.

anonymous
()
Ответ на: комментарий от PPP328

Согласен. Но ты не понял идею моего комментария, она заключается в том, что тебе надо мониторить не процесс, а факт изменения файла отчёта.

DELIRIUM ☆☆☆☆☆
()

В своей программе делаешь

prctl(PR_SET_CHILD_SUBREAPER);

и тогда p2 после смерти p1 станет ребенком твоей программы, а не ребенком init. Потом делаешь wait() до тех пор, пока он не скажет, что больше нет детей.

ttnl ★★★★★
()
Ответ на: комментарий от DELIRIUM

Мы сейчас это делаем. И это работает плохо - файл может не обновиться из-за того, что p2 завершился с ошибкой. Файл может обновиться, но у нас сработал timeout. И пр.

PPP328 ★★★★★
() автор топика
Ответ на: комментарий от ttnl

Вах, родной, дай я тебя расцелую!

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#include <errno.h>

int main(void) {

    char *newargv[] = { NULL };
    char *newenviron[] = { NULL };

    printf("MAIN: My pid is %d, my daddy is %d\n", getpid(), getppid());

    prctl(PR_SET_CHILD_SUBREAPER);

    int pid = fork();
    if (pid == 0) {
        // child
        execve("./p1.elf", newargv, newenviron); 
    } else {
        // main
        int status;
        int pid;
        while ((pid = wait(&status)) > 0);
    }

    printf("p1 exited\n");
    return 0;
}

Осталась другая проблема - как это под винду портировать.

PPP328 ★★★★★
() автор топика
Ответ на: комментарий от PPP328

1)На счет венды — ХЗ. 2)Имей ввиду, что prctl() может возвращать ошибку/

ttnl ★★★★★
()
Ответ на: комментарий от PPP328

Вах, родной, дай я тебя расцелую!

Я это первый предложил.

anonymous
()
Ответ на: комментарий от st4l1k

И? Под виндой другой механизм и другие функции, как мне твой ифдеф поможет?

PPP328 ★★★★★
() автор топика
Ответ на: комментарий от cdslow

Звучит вкусно. Если это завезли во всех NT'ях, и оно работает как ожидается (wait { p & }) то подойдет, спасибо.

PPP328 ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.