Fork() 未在父进程中返回 id > 0

Fork() is not returning an id > 0 in the parent process

我目前正在尝试了解 fork() 和一般流程。

我的任务是执行 fork() 一定次数 - n - 用户可以输入。另外,我应该使用 waitpid() 来等待我的进程终止。每个进程都应该 return 一个介于 1 和 6 之间的随机数。

到目前为止,这是我的代码:

#include <time.h>
#include <stdlib.h>
#include <stdio.h>

int main(){

  int n,i;
  int *returnvalue;
  int pid;
  int waitingID;

  time_t t;
  srand((unsigned)time(&t));

  printf("How many processes to start?\n");
  scanf("%d",&n);

  for(i=0; i < n; i++){
    pid = fork();
    if(pid==0){
      printf("I am %d, from iteration %d\n",getpid(), i);
    }
    else if(pid > 0){
      waitingID = waitpid(pid, returnvalue, 0);
      printf("Return-value of %d is: %d\n", waitingID, *returnvalue);
    }
    else{
      printf("A problem occured.");
    }
  }

  return rand()%6;
}

这是当前程序的示例输出:

How many processes to start?
5
I am 6449, from iteration 0
I am 6450, from iteration 1
I am 6451, from iteration 2
I am 6452, from iteration 3
I am 6453, from iteration 4
Segmentation fault (core dumped)

如您所见,我遇到了一些问题:

根本没有调用 else if (pid>0)。因此不会发生等待。对于相应的父进程,不应该在每个 fork 中调用它吗?

此外,一旦最后一次迭代结束并到达 return,我就会收到分段错误(核心转储)错误。

我现在迷路了。我不太明白我的错误在哪里。

您没有得到 parent 案例的任何输出,因为 parent 进程 waitpid 导致了分段错误。 returnvalue 是任何未初始化的指针。您需要这样做:

int returnvalue;
...
pid = fork();
if(pid==0){
  printf("I am %d, from iteration %d\n",getpid(), i);
}
else if(pid > 0){
  waitingID = waitpid(pid, &returnvalue, 0);
  printf("Return-value of %d is: %d\n", waitingID, returnvalue);
}

但即使那样也不是您真正想要的。 waitpid 中的 return 值不应按原样使用。您需要使用 WIF 宏来确定 child 存在状态,然后使用 WEXITSTATUS 宏来获取 return 值。这是手册页中的示例:

if (WIFEXITED(status)) {
    printf("exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
     printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
     printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
     printf("continued\n");
}
int *returnvalue;

这只是一个指向 int 指针 ,但指向未定义的位置,因此:

waitingID = waitpid(pid, returnvalue, 0);

会将状态代码写入某个可能不属于您的进程的随机内存位置(根据,通过未初始化的指针写入是未定义的行为)。

简单的事情,而不是定义一个指针,定义一个实际的 int 变量:

int returnvalue;

并传递指向该变量的指针:

waitingID = waitpid(pid, &returnvalue, 0);

函数waitpid 尝试写入returnvalue 指向的存储。在您的代码中 returnvalue 尚未初始化,因此 它的值是未定义的。

由于 waitpid 正在尝试写入未知地址,因此导致崩溃。

按照其他人的建议,缓解这种情况的一种方法是使用 int returnvalue,然后将其地址作为 &returnvalue 传递给 waitpid。 这样,由于变量 returnvalue 是在堆栈上创建的,因此它的地址定义明确并且 waitpid 也可以写入它。

你可以做的另一个值是调用 malloc 并给你的指针一个地址(将在堆而不是堆栈上创建的存储)所以它不是很有效然后你可以将它传递给 waitpid。但是不要忘记在之后调用 free

returnvalue = malloc(sizeof(int));
waitingID = waitpid(pid, returnvalue, 0);
printf("Return-value of %d is: %d\n", waitingID, *returnvalue);
free(returnvalue);