使用 fork() 创建进程树然后给它们编号并在数组上显示

塔穆诺

我试图了解在 Linux 上工作的 fork() 系统调用,这就是我编写以下 C 程序的原因:

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

int main(int argc, char *argv[]) {
  int n = atoi(argv[1]);
  int i;
  pid_t pid;
  printf("Main:    PID: %d, PPID:%d\n", getpid(), getppid());
  for (i = 0; i <= n; i++) {
    if (pid = fork()) {
      pid = fork();
      if (pid > 0) {
        return (0);
      }
      if (i == n) {
        printf("We are in the level %d and as a child PID:%d,PPID:%d\n", n,
               getpid(), getppid());
      }
    }
  }
  return 0;
}

我所做的是:创建一个深度为 n 的进程树,其中每个进程创建 2 个子进程然后终止。最后我只是打印了最后一级的孩子 pid(所以如果 n=3,将有 8 个孩子,我想看看这些孩子的 pid)。根据我的理解,代码运行正常。(如果有任何错误,请纠正我)。

在这一点之后,我想改变我的代码来做这样的事情:

        1
       / \
      /   \
     /     \
    /       \
   2         3
  / \       / \
 /   \     /   \
4     5   6     7

例如,如果 n=2。我想打印出如下内容:

Last Level Children: 1 2 4
Last Level Children: 1 2 5
Last Level Children: 1 3 6
Last Level Children: 1 3 7

为此,我编写了以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define SIZE 256

int main(int argc, char *argv[]) {
  int n = atoi(argv[1]);
  int i, k;
  int m = 1;
  int j = 0;
  int arr[SIZE];
  pid_t pid;
  arr[j] = m;
  m++;
  j++;
  for (i = 0; i <= n; i++) {
    pid = getpid();
    if (pid = fork()) {
      arr[j] = m;
      m++;
      j++;
      pid = fork();
      if (pid > 0) {
        arr[j] = m;
        m++;
        j++;
        return (0);
      }
      if (i == n) {
        printf("Process tree: ");
        for (k = 0; k <= n; k++) {
          printf("%d ", arr[k]);
        }
        printf("\n");
      }
    }
  }
  return 0;
}

但是当我运行程序时,我似乎得到了错误的结果。我在这里做错了什么?任何在正确方向上的帮助表示赞赏。

观星者

你的主要问题是你的孩子会继续他们父母的循环并创造更多你认为的孩子。我只能建议你读两次的曼努埃尔fork()管理流程创建并不容易。您需要了解您的孩子会复制 (~) 其父母的所有状态。两者都将执行相同的代码,因此您需要注意在您的 fork 之后将执行哪些代码取决于fork().

EOF评论是为了建议您不要fork()在函数中使用更多。您会看到我的实现示例通过没有两个fork()调用来保持简单,我将调用隔离在一个特定的地方。

这是您的第一个代码的正确实现:

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

static int create_two_child(int i, int n);

int main(void) { return create_two_child(0, 2); }

// tail recursive function: child will call this function to create two new
// child
static int create_two_child(int i, int n) {
  if (i < n) { // we look our level
    // debug output
    printf("DEBUG: We are in the level %d and as a child PID:%d, PPID:%d\n", i,
           getpid(), getppid());
    fflush(stdout); // we don't want child print parent output
    for (int j = 0; j < 2; j++) { // we loop to create two child
      pid_t pid = fork();
      if (pid == -1) { // error
        perror("fork()");
        return 1;
      } else if (pid == 0) {               // child
        return create_two_child(i + 1, n); // we call ourself with i + 1 and
                                           // stop function here wich return we
                                           // don't want that child continue the
                                           // loop
      }
      // parent will continue the loop to the number of child wanted
    }
  } else {
    // if we are at max level we show our pid
    printf("We are in the level max %d and as a child PID:%d, PPID:%d\n", i,
           getpid(), getppid());
  }
  return 0;
}

您想要显示树的第二个实现:

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

static int create_two_child(size_t *backtrace, size_t id, size_t i, size_t n);

int main(void) {
  // we create array to stock id
  size_t backtrace[3];
  size_t n = sizeof backtrace / sizeof *backtrace;
  return create_two_child(backtrace, 1, 0, n);
}

// tail recursive function: child will call this function to create two new
// child
static int create_two_child(size_t *backtrace, size_t id, size_t i, size_t n) {
  if (i < n) {                       // we look our level
    for (size_t j = 0; j < 2; j++) { // we loop to create two child
      pid_t pid = fork();
      if (pid == -1) { // error
        perror("fork()");
        return 1;
      } else if (pid == 0) { // child
        backtrace[i] = id + 1;
        // id * 2 cause we create 2 child each time
        return create_two_child(backtrace, id * 2, i + 1,
                                n); // we call ourself with i + 1 and
                                    // stop function here wich return we
                                    // don't want that child continue the
                                    // loop
      }
      id++;
      // parent will continue the loop to the number of child wanted
    }
  } else {
    // if we are at max level we show our backtrace
    printf("Last Level Children: 1");
    for (size_t j = 0; j < n; j++) {
      printf(", %zu", backtrace[j]);
    }
    printf("\n");
  }
  return 0;
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用fork创建多个进程

来自分类Dev

使用fork创建多个进程

来自分类Dev

在C语言中使用fork()创建特定的进程树

来自分类Dev

显示使用fork循环的进程数

来自分类Dev

如何使用fork创建并行子进程

来自分类Dev

fork git 分支并使用 SmartGit 查看它们

来自分类Dev

计算在for循环中使用fork创建的进程数

来自分类Dev

使用fork创建新进程,但为变量打印相同的地址

来自分类Dev

使用fork()遍历目录

来自分类Dev

在UNIX中使用fork

来自分类Dev

使用fork:从父级访问子进程内存

来自分类Dev

进程使用fork运行xterm实例时出错

来自分类Dev

在shell中使用fork命令来打印进程ID

来自分类Dev

在使用fork()创建的C语言中,将子进程中的值返回给其父进程

来自分类Dev

父进程中的Fork()

来自分类Dev

如何正确fork()进程

来自分类Dev

子进程从创建时的第一行开始(使用fork)

来自分类Dev

当父级使用fork时,子级进程是在连续的内存空间中创建的吗?

来自分类Dev

使用 fork() 创建新进程时写时复制优化的优点

来自分类Dev

使用fork和kill信号

来自分类Dev

使用Fork时的输出窗口

来自分类Dev

使用fork()和pipe()的IPC

来自分类Dev

使用 fork() 时的奇怪输出

来自分类Dev

Fork 数组赋值冲突

来自分类Dev

使用waitpid pselect fork sigaction使用处理程序清理子进程

来自分类Dev

为什么glibc的fork实现不使用sys_fork?

来自分类Dev

Linux系统使用Fork()将int传递给子进程和父进程来调用问题

来自分类Dev

在C中使用两个fork()时如何利用每个进程

来自分类Dev

使用fork和MPI进行多进程编程之间的区别