使用fork()创建进程树然后对它们进行编号并在数组

时间:2017-11-04 16:56:26

标签: c linux process fork

我正在尝试理解fork()系统调用以在Linux上工作,这就是我编写以下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个子进程然后终止。最后我刚刚打印出最后一级的儿童pids(所以如果n = 3,将有8个孩子,我想看到这些孩子的pids)。根据我的理解,代码工作正常。(如果有任何错误,请纠正我。)

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

        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;
}

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

1 个答案:

答案 0 :(得分:0)

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

EOF的manuel是建议你在一个函数中没有那个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;
}

第二个实现,你想要显示树:

'DIRS': [str(ROOT_DIR.path('polls/templates/polls/')),],