遇到问题 运行 2 个子进程

Having trouble running 2 child processes

在这个程序 mulproc.c 中,我试图 运行 我制作的两个程序的可执行文件(一个计算文件中字母字符的数量,另一个计算五个特定的特殊字符人物)。我正在尝试创建一个父进程(在这种情况下只是 mulproc.c),这两个程序 运行 都在它们自己的子进程中,所以基本上只需从父进程创建两个子进程。这两个程序各自有自己的输出,但围绕着各自的输出,我还想为每个程序输出两条消息,指示何时开始和何时结束。然而,每次不同的尝试我都会得到不正确的和不同的输出(我不想在这里 post 它们全部)。我的两个程序的输出甚至被写在彼此之间,所以我相信我可能错误地使用了 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!

如果有人能在这里纠正我的错误,我真的很感激...我对使用这样的系统调用是全新的,所以希望我在这种情况下不会搞砸太多。

如果您不希望进程运行 并行,则必须等待第一个进程完成,然后再启动第二个进程。所以用伪代码写的,而不是这样做:

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

waitpid(pid1);
waitpid(pid2);

你必须做的:

pid1 = launch_proc1();
waitpid(pid1);

pid2 = launch_proc2();    
waitpid(pid2);

如何将伪代码转换为正确的 c 作为练习留给 reader。

编辑:关于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_proc1launch_proc2 组合成一个 int launch_proc(const char *cmd)

@HAL9000 说的对,

但为了简洁起见,我将重新措辞:

在你第一次分叉后,你只需要输入:

waitpid(YOUR_CHILD_PID, NULL, 0);

在你再次 fork 之前在父进程中。

一般来说,进程可以在循环中创建。在每个 fork 之后,在父进程中(pid > 0),您等待刚刚创建的子进程。

否则,你有竞争条件(进程之间的竞争),结果是你的未定义行为。

根据内核调度进程的顺序,您每次都会得到不同的输出。

我想你知道这一点。您遇到的主要问题是您在等待第一个过程之前创建了第二个过程。因此进程的调度顺序未定义。

如果您不希望两个子进程的输出混合,在这种情况下,等待第一个子进程完成,然后启动下一个。如果您希望两个并发进程的输出不应该混合,一般来说,创建一个名为 print_process 的特殊进程。进程应该向 print_process 发送消息,而不是直接打印。而且,print_process,应该写在终端上。