Возникли проблемы с запуском 2 дочерних процессов

В этой программе mulproc.c я пытаюсь запустить исполняемые файлы двух программ, которые я сделал (одна считает количество буквенных символов в файле, а другая подсчитывает пять определенных специальных символов). Я пытаюсь создать родительский процесс (в данном случае просто mulproc.c), который запускает эти две программы, каждая в своем собственном дочернем процессе, поэтому просто создайте два дочерних процесса из родителя. Каждая из двух программ имеет свой собственный вывод, но вокруг соответствующих выходов я также хочу вывести два сообщения для каждой, указывающих, когда она начинается и когда заканчивается. Однако я получаю неправильные и разные результаты с каждой новой попыткой (я не хочу публиковать их все здесь). Выводы двух моих программ даже записываются между собой, поэтому я полагаю, что могу неправильно использовать функцию waitpid(). Более того, у меня возникают проблемы с распечаткой правильных PID дочерних процессов в родительском процессе. Пожалуйста, игнорируйте две метки номера дочернего процесса в целях отладки, поскольку они неуместны. Вот mulproc.c...

#include <stdio.h>
#include "count.h"
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h> 
#include <stdbool.h>
#include <dirent.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>

int main( int argc, char *argv[] )
{       
    pid_t pid1;
    pid_t pid2;
    int status1;
    int status2;

    pid1 = fork();

    if ( pid1 < 0 )
    {
        perror( "ERROR! Fork failed!" );
        exit(1);
    }

    if ( pid1 == 0 )
    {
        // CHILD PROCESS CODE

        printf( "\nChild Process 2:\npid :%d\nppid:%d\n\n", getpid(), getppid() );

        printf( "CHILD <PID: %d> process is executing testspecial program!\n", getpid() );

        char *specialchar[] = { "./testspecial" , NULL };
        execv( specialchar[0], specialchar );   
    }

    if ( pid1 > 0 )
    {

        pid2 = fork();

        if ( pid2 == 0 )
        {
            // ANOTHER CHILD PROCESS CODE

            printf( "\nChild Process 1:\npid :%d\nppid:%d\n\n", getpid(), getppid() );

            printf( "CHILD <PID: %d> process is executing testalphabet program!\n", getpid() );

            char *alphabetchar[] = { "./testalphabet" , NULL };
            execv( alphabetchar[0], alphabetchar );
        }

        else if ( pid2 > 0 )
        {
            // PARENT PROCESS CODE

            printf( "\nParent Process:\npid:%d\nppid :%d\n", getpid(), getppid() );

            // if child1 terminated...

            if ( waitpid( pid1, &status1, 0 ) == pid1 )
            {
                printf( "CHILD <PID: %d> process has done with testalphabet program! See the results above!\n", getpid() );
            }

            // if child2 terminated...

            if ( waitpid( pid2, &status2, 0 ) == pid2 )
            {
                printf( "CHILD <PID: %d> process has done with testspecial program! See the results above!\n", getpid() );
            }
        }

    }


    return 0;
    
}

и вот только ОДИН из неправильных выводов...

Parent Process:
pid:3166
ppid :3149

Child Process 1:
pid :3168
ppid:3166

CHILD <PID: 3168> process is executing testalphabet program!

Child Process 2:
pid :3167
ppid:3166

CHILD <PID: 3167> process is executing testspecial program!
A -> 0
B -> 0
C -> 0
D -> 0
E -> 0
F -> 0
G -> 0
H -> 3
I -> 0
J -> 0
K -> 0
L -> 0
M -> 0
N -> 0
O -> 0
P -> 0
Q -> 0
, -> 1
R -> 0
S -> 0
T -> 0
. -> 1
U -> 0
: -> 1
V -> 0
; -> 1
W -> 0
! -> 1
X -> 0
Y -> 0
Z -> 3
a -> 0
b -> 0
c -> 0
d -> 0
e -> 0
f -> 0
g -> 0
h -> 3
i -> 0
j -> 0
k -> 0
CHILD <PID: 3166> process has done with testalphabet program! See the results above!
l -> 0
m -> 0
n -> 0
o -> 0
p -> 0
q -> 0
r -> 0
s -> 0
t -> 0
u -> 0
v -> 0
w -> 0
x -> 0
y -> 0
z -> 0
CHILD <PID: 3166> process has done with testspecial program! See the results above!

Я ХОЧУ, чтобы результат выглядел примерно так...

CHILD <PID: 3168> process is executing testalphabet program!
A -> 0
B -> 0
C -> 0
...
...
...
x -> 0
y -> 0
z -> 0
CHILD <PID: 3168> process has done with testalphabet program! See the results above!
CHILD <PID: 3167> process is executing testspecial program!
, -> 1
. -> 1
: -> 1
; -> 1
! -> 1
CHILD <PID: 3167> process has done with testspecial program! See the results above!

Действительно очень ценю, если кто-нибудь может исправить мои ошибки здесь... Я новичок в использовании подобных системных вызовов, поэтому, надеюсь, в этом случае я не слишком много испортил.


person PluffTed    schedule 11.07.2020    source источник
comment
по поводу: #include "count.h" Мы не можем воспроизвести проблему, так как опубликованный код не компилируется. Пожалуйста, опубликуйте содержимое count.h   -  person user3629249    schedule 12.07.2020
comment
OT: относительно: int main( int argc, char *argv[] ) Параметры не используются. В результате компилятор выводит два предупреждающих сообщения о неиспользуемых параметрах. Простым решением было бы использовать другую действительную подпись для main(). int main( void )   -  person user3629249    schedule 12.07.2020
comment
Внимательное изучение показывает, что НИЧЕГО в заголовочном файле count.h не используется. Поэтому этот заголовочный файл не должен быть включен.   -  person user3629249    schedule 12.07.2020
comment
что происходит, когда pid2 равно ‹0 ?   -  person user3629249    schedule 12.07.2020
comment
OT: это очень плохая практика программирования - включать файлы заголовков, содержимое которых не используется: Предложите удалить: #include <string.h> и #include <ctype.h> и #include <stdbool.h> и #include <dirent.h> и #include <errno.h>   -  person user3629249    schedule 12.07.2020
comment
относительно такого рода утверждений: execv( specialchar[0], specialchar ); вызов execv() может завершиться ошибкой, тогда дочерний элемент будет выполнять код, которого он не должен. Предложить: execv( specialchar[0], specialchar ); perror( "execv for specialchar failed" ); exit( EXIT_FAILURE );   -  person user3629249    schedule 12.07.2020


Ответы (3)


Если вы не хотите, чтобы процессы выполнялись параллельно, вам нужно дождаться завершения первого, прежде чем запускать второй. Так написано в псевдокоде, а не так:

pid1 = launch_proc1();
pid2 = launch_proc2();

waitpid(pid1);
waitpid(pid2);

Ты должен сделать:

pid1 = launch_proc1();
waitpid(pid1);

pid2 = launch_proc2();    
waitpid(pid2);

Как перевести псевдокод в правильное с, оставляем читателю в качестве упражнения.

РЕДАКТИРОВАТЬ: некоторые разъяснения по launc_procX:

Предполагается, что launc_procX реализует комбинацию fork/exec.

int launc_proc1()
{
    int pid = fork();

    if ( pid < 0 )
    {
        perror( "ERROR! Fork failed!" );
        exit(EXIT_FAILURE);
    }

    else if (pid == 0)
    {
        // CHILD PROCESS CODE

        printf( "\nChild Process 2:\npid :%d\nppid:%d\n\n", getpid(), getppid() );

        printf( "CHILD <PID: %d> process is executing testspecial program!\n", getpid() );

        char *specialchar[] = { "./testspecial" , NULL };
        execv( specialchar[0], specialchar );

        // Handle failure of exec (this is important !!!!!)
        perror( "ERROR! exec failed!" );
        exit(EXIT_FAILURE);
    }
    // because execv is supposed to never return,
    // only parent is able to reach this point

    return pid;
}

Естественно, вы можете объединить launch_proc1 и launch_proc2 в один int launch_proc(const char *cmd).

person HAL9000    schedule 11.07.2020
comment
Я знаю, вы сказали, что это псевдокод, но не могли бы вы рассказать о launch_proc() ? - person PluffTed; 12.07.2020
comment
Эй, большое спасибо за разработку, я очень ценю это..... еще один вопрос, хотя..... внутри launc_proc1() после execv() я пытаюсь вывести сообщение пользователю перед функцией (процесс в этом случае) выходит. Однако мое сообщение даже не выводится, и я думаю, это потому, что execv() запрещает мне это делать. Есть ли способ обойти это? - person PluffTed; 12.07.2020
comment
когда execv() успешно, он НЕ возвращается. - person user3629249; 12.07.2020

@HAL9000 прав,

но для краткости перефразирую:

после вашей первой вилки вам нужно только поставить:

waitpid(YOUR_CHILD_PID, NULL, 0);

в родительском процессе ПЕРЕД тем, как вы снова разветвитесь.

как правило, процессы могут создаваться в цикле. где после каждой вилки в родительском процессе (где pid > 0) вы ждете только что созданного дочернего процесса.

в противном случае у вас есть состояние гонки (гонка между вашими процессами), и результатом является ваше неопределенное поведение.

каждый раз вы получаете разные выходные данные в зависимости от порядка, в котором ядро ​​планирует процессы.

Я думаю, ты знаешь это. основная проблема заключается в том, что вы создаете второй процесс, прежде чем ждать первого. поэтому порядок запланированных процессов не определен.

person Kiefer_Michael    schedule 12.07.2020

Если вы не хотите, чтобы выходные данные двух дочерних процессов смешивались, в этом случае дождитесь завершения первого дочернего процесса, а затем запустите следующий. Если вы хотите, чтобы вывод двух параллельных процессов не смешивался, вообще создайте специальный процесс с именем, скажем, print_process. Вместо прямой печати процесс должен отправить сообщение процессу print_process. И print_process должен писать на терминале.

person kjohri    schedule 12.07.2020