使用 switch 语句 fork 两个进程

Using switch statements to fork two processes

我正在学习 C 课程的介绍,但我对第一个作业有点难过。我们的任务是创建一个父进程和两个子进程。到目前为止,本书向我们展示的所有示例都涉及一个父子关系的 switch 语句。我对如何将其转化为一个父进程和两个子进程感到有点困惑。这是我目前所拥有的:

#include <stdio.h>

int main() {
    int i, pid, status;
    pid = fork();
    switch(pid) {
    case -1:
        /* An error has occurred */
        printf("Fork Error");
        break;
    case 0:
        /* This code is executed by the first parent */
        printf("First child process is born, my pid is %d\n", getpid());
        printf("First child parent process is %d\n", getppid());
        for (i=1; i<=10; i++)
            printf("First child process, iteration: %d\n", i);
        printf("First child dies quietly.\n");
        break;
    default:
        /* This code is executed by the parent process */
        printf("Parent process is born, my pid is %d\n", getpid());
        wait(&status);
        printf("Parent process dies quietly.\n");
    }
}

这非常适合这一过程:

Parent process is born, my pid is 10850
First child process is born, my pid is 10851
First child parent process is 10850
First child process, iteration: 1
First child process, iteration: 2
First child process, iteration: 3
First child process, iteration: 4
First child process, iteration: 5
First child process, iteration: 6
First child process, iteration: 7
First child process, iteration: 8
First child process, iteration: 9
First child process, iteration: 10
First child dies quietly.
Parent process dies quietly.

基本上我只需要用第二个过程做同样的事情......就像:

printf("Second child process is born, my pid is %d\n", getpid());
printf("Second child parent process is %d\n", getppid());
for (k=1; k<=10; k++)
    printf("Second child process, iteration: %d\n", i);
printf("Second child dies quietly.\n");
break;

但我只是不确定如何从目前的情况出发。我正在接近这种正确的方式吗?我应该使用更好的方法吗?非常感谢。

要生成 2 child,您需要调用 fork()2x。所以用 2 个不同的变量调用 fork,然后等待它们。

您可以将 fork 和 switch case 放在循环中,以便它 fork 多个进程,如下所示:

编辑:您可以删除 if 条件以在每次分叉后调用 wait,或者如果您想要启动所有子项然后等待它们终止,在每次迭代中您可以收集 pid每个子进程(在父进程中,即在默认切换情况下)在一个数组中,并在最后一次迭代中循环调用 waitpid(对于每个 pid)以确保每个子进程都已退出

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
    int i, pid, status;
    int j = 0;
    int numChildren = 2;/*Change it to fork any number of children*/
    for(j = 0;j< numChildren;j++)
    {
            pid = fork();
            switch(pid) {
            case -1:
                /* An error has occurred */
                printf("Fork Error");
                break;
            case 0:
                /* This code is executed by the first parent */
                printf("First child process is born, my pid is %d\n", getpid());
                printf("First child parent process is %d\n", getppid());
                for (i=1; i<=10; i++)
                    printf("First child process, iteration: %d\n", i);
                printf("First child dies quietly.\n");
                exit(0);/*Otherwise it will fork its own child*/
                break;
            default:
                /* This code is executed by the parent process */
                printf("Parent process is born, my pid is %d\n", getpid());
                if(j == (numChildren - 1))/*You can remove this condition to wait after each fork*/
                {
                wait(&status);
                printf("Parent process dies quietly.\n");
                }
            }
        }
}

有一个通用规则。当您使用 fork(2) 时,您应该 始终处理下面的 三种 情况

  1. fork给了0,你在child进程
  2. fork给正pid_t,你在parent过程
  3. fork 失败 并给了-1

人们(新手)有时容易忘记上次(失败)的案例。但它确实发生了,你可以通过使用 setrlimit(2) with RLIMIT_NPROC in your grand-parent process to lower the limit on processes, often that grand-parent process is your shell (e.g. using ulimit Bash builtin-u).

轻松测试这种情况

现在,如何处理这三种情况是编码风格的问题。您可以使用 switch,但您可以使用两个 if。您的代码使用 switch 并且这样做是正确的。

作为一般规则,大多数 system calls (listed in syscalls(2)) can fail, and you almost always need to handle the failure case (see errno(3) and use perror(3))。

另请阅读 Advanced Linux Programming(可免费下载)。

I'm a bit confused about how to translate this into one parent and two child processes.

fork 系统调用正在创建(成功时)正好 一个 child 进程。所以如果你需要两个 children,你应该连续调用它两次(并在两次调用中测试失败)。如果你需要一个child和一个盛大child,你应该只在第一个给0时才做第二个fork。当然你需要同时保留两个(成功和积极)pid_t -例如在两个变量中 - 由您对 fork.

的两次调用返回

避免zombie processes, every successful fork should later have its wait system call (e.g. waitpid(2) or wait or wait4(2)wait3)。你在哪里等待取决于你是否想同时拥有 children 运行。但是每个成功的 fork 都应该有一个相应的成功 wait 调用。

另请阅读 signal(7) (and signal-safety(7)) about SIGCHLD if you want to be asynchronously notified about child processes change - notably termination. A common way is to install a SIGCHLD signal handler (e.g. using sigaction(2) or the old signal(2)) which just sets some global volatile sigatomic_t flag and test then clear that flag in convenient place in your code (e.g. in some event loop using poll(2))。

注意:注意 fork 不是关于 C 编程的(fork 不是 C11 standard n1570 or its predecessor C99). It is a POSIX and Linux thing. Windows or z/OS or an Arduino 微控制器中定义的没有它本机,但在某些标准 C 中是可编程的。