【问题标题】:Using switch statements to fork two processes使用 switch 语句来分叉两个进程
【发布时间】:2017-06-01 01:45:50
【问题描述】:

我正在学习 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;

但我只是不知道如何从我目前所掌握的情况下到达那里。我正在接近这种正确的方式吗?我应该使用更好的方法吗?非常感谢。

【问题讨论】:

  • 您可能想了解更多关于forking
  • 您只是使用switch 来检查fork 的返回(您也可以使用if..then..else)。只需调用fork 两次并检查两个返回(例如两个完整的fork / switch 块)。然后你有一个父母,两个孩子。
  • 您缺少 Linux 或 POSIX 标签。
  • 您的问题是关于将switch 用于fork 还是关于如何创建两个子进程?我对您的问题投了反对票,因为它的重点不明确,而且这确实是两个非常不同且独立的问题。

标签: c linux posix


【解决方案1】:

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

  1. fork 给了 0,你在 child 进程中
  2. fork 给了一个肯定的pid_t,你在进程中
  3. fork 失败并给出-1

人们(新手)有时会忘记最后一个(失败)案例。但它确实发生了,您可以通过在祖父进程中使用 setrlimit(2)RLIMIT_NPROC 来轻松测试这种情况,以降低对进程的限制,通常祖父进程是您的外壳(例如,使用 ulimit Bash builtin-u)。

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

作为一般规则,大多数system calls(在syscalls(2) 中列出)可能会失败,并且您几乎总是需要处理失败情况(请参阅errno(3) 并使用perror(3))。

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

我对如何将其转换为一个父进程和两个子进程感到有些困惑。

fork 系统调用正在创建(成功时)恰好一个子进程。因此,如果您需要两个孩子,您应该连续调用两次(并在两次调用中测试失败)。如果你需要一个孩子和一个孙子,你应该做第二个fork,只有当第一个给0时。当然你需要保持两者(成功和积极)pid_t -e.g.在两个变量中 - 由您对 fork 的两次调用返回。

为避免zombie processes,每个成功的fork 都应稍后有其等待系统调用(例如waitpid(2)waitwait4(2)wait3)。你在哪里等待取决于你是否想让两个孩子同时跑步。但是每个成功的fork 都应该有一个对应的成功的wait 调用。

如果您想异步收到有关子进程更改(尤其是终止)的通知,另请阅读signal(7)(和signal-safety(7))关于SIGCHLD。一种常见的方法是安装一个SIGCHLD 信号处理程序(例如使用sigaction(2) 或旧的signal(2)),它只设置一些全局volatile sigatomic_t 标志并测试然后在代码中方便的位置清除该标志(例如在某些event loop 使用 poll(2))。

注意:请注意 fork 与 C 编程无关(fork C11 标准 n1570 或其前身 C99 中定义)。这是POSIX 和 Linux 的事情。 Windows 或 z/OSArduino 微控制器本身没有它,但可以在某些标准 C 中进行编程。

【讨论】:

  • 我改进了我的答案。如果你需要两个孩子,你应该做两个forks。
【解决方案2】:

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

编辑:您可以在每次分叉后删除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");
                }
            }
        }
}

【讨论】:

  • 您只wait 一次,而您应该为所有子进程wait
【解决方案3】:

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

【讨论】:

  • 我认为我的评论比较长,也许在回答中需要更多解释?
猜你喜欢
  • 2019-11-20
  • 2013-02-19
  • 2013-05-18
  • 1970-01-01
  • 2015-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多