1

我正在编写一个小程序,它在命令行中输入一个数字,并使用 fork() 创建一个对数字的数字求和的进程链。到目前为止,情况如下:

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

int main(int argc, char* argv[]){

  if(argc != 2){
    printf("Usage: sod [number] \n");  /* -o sod when compiled */
    exit(1); 
  }

  pid_t childpid = 0; 
  int sum = 0;   

  int i; 
  for(i = 0; i < strlen(argv[1]); i++){
    /* atoi needs a string */
    char str[2]; 
    str[0] = argv[1][i]; str[1] = 0;  
    sum += atoi(str);   
    if(childpid = fork()) 
      break;  
  }

  wait(NULL); 
  printf("sum: %d\n", sum);
  exit(0); /* probably redundant... */
  return 0; 
}

根据我在系统手册中的理解,if 语句确保进程在一个链中(每个父进程可以有一个子进程,并且继续向下),因为fork()将子进程的 id 返回给父进程,将 0 返回给孩子。因此,分配的结果对于父级来说是非零/真,并强制它从循环中中断:

 if(childpid = fork()) 
          break; 

在我添加wait(NULL)调用之前,该函数打印了多行总和,不一定按顺序打印,我认为这应该是预期的,因为进程在不同的时间完成。有趣的是,如果我用大量数字(如 11221121)调用程序,它有时会打印一些总和,在它们中间输出我的 shell 提示符,并在挂在那里之前再打印一些,就像在无限中一样环形:

[nvj]@sun ~/313/sod> (12:15:21 02/10/13)
:: sod 11221121
sum: 1
sum: 2
sum: 4
sum: 6
sum: 7
sum: 8
sum: 10

[nvj]@sun ~/313/sod> (12:15:24 02/10/13)
:: sum: 11
sum: 11
[hangs here...]

对于为什么会发生这种情况,我唯一的猜测是某些事情正在超时,或者需要等待其他人的事情正在陷入困境。为了使程序真正结束(并以某种顺序打印总和),我添加了wait(NULL)调用。据我所知,它迫使父母在继续之前等待其所有孩子。不出所料,这会导致实际总和在最后一个创建的孩子完成时首先打印,然后让其余的按顺序进行:
[

nvj]@sun ~/313/sod> (12:25:02 02/10/13)
:: sod 12389492182398
sum: 69
sum: 69
sum: 61
sum: 52
sum: 49
sum: 47
sum: 39
sum: 38
sum: 36
sum: 27
sum: 23
sum: 14
sum: 6
sum: 3
sum: 1

值得庆幸的是,程序实际上在这种情况下结束。但是,当具有实际总和的孩子返回并显示其结果时,有没有办法让它结束呢?我已经尝试过诸如平面调用之类的东西exit(如您所见......),但这似乎在与子进程不同的“领域”中运行,并且在第一次打印后不会立即发生。

4

1 回答 1

2

使用fork()是一种对数字求和的非常昂贵的方法。您可以使用 Web 服务来代替;那会更慢。

所以,作为一个训练练习,你需要意识到每个孩子都有自己的变量副本。第 N 个子进程无法影响其sum任何父进程中的值 - 除非您进入共享内存等。

当你说:

sum: 10

[nvj]@sun ~/313/sod> (12:15:24 02/10/13)
:: sum: 11
sum: 11
[hangs here...]

shell 会事先提示您,并等待您的输入。如果您echo Hi在 'hung' shell 中键入,您将看到Hiechoed 并且您的提示符正常。它只是意味着您的父进程在最后一个孩子完成写作之前完成。

在你放入之前wait(),你的第一个进程分叉,退出循环,打印它的值,然后退出,让 shell 再次提示。同时,第一个孩子在做自己的事情,第二个孩子在做自己的事情,每个孩子都在分叉和退出,事情发生的顺序由调度程序决定。

wait()就位后,孩子(和它的孩子(和它的孩子(和它的孩子......)))已经完成了它的输出,你会以确定的顺序得到答案。

最后一个孩子有前一个孩子累积的数字之和,这意味着只有最后一个孩子需要打印任何东西才能得到最终的总和。

其中一个语句是多余exit(0);的。return(0);我建议使用return(0);代替exit(0);

于 2013-02-10T18:37:59.153 回答