我正在编写一个小程序,它在命令行中输入一个数字,并使用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到子进程。因此,对于父项,赋值的结果为非零/ true,并强制它从循环中断开:
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
之类的东西(正如你所看到的......),但这似乎与子进程在不同的“领域”中运行,并且在第一次打印之后不会立即发生。
答案 0 :(得分:2)
使用fork()
是一种非常昂贵的方法来对数字的数字求和。你可以用Web服务代替它;那会慢一些。
因此,作为一项训练练习,您需要意识到每个孩子都有自己的变量副本。第N个孩子无法在任何父进程中影响sum
的值 - 除非你进入共享内存等等。
当你说:
sum: 10
[nvj]@sun ~/313/sod> (12:15:24 02/10/13)
:: sum: 11
sum: 11
[hangs here...]
shell事先提示你,正在等待你的输入。如果您在“挂起”的shell中键入echo Hi
,您会看到Hi
已回显并且您的提示正常。它只是意味着您的父进程在最后一个孩子写完之前就已完成。
在放入wait()
之前,您的第一个进程分叉并退出循环,并打印其值,然后退出,允许shell再次提示。与此同时,第一个孩子正在做它的东西,第二个孩子正在分叉和退出,事情发生的顺序由调度员决定。
在wait()
到位后,孩子(及其子女(及其子女(及其孩子......)))已完成输出,您将以确定的顺序获得答案。
最后一个孩子拥有前一个孩子累积的数字总和,这意味着只有最后一个孩子需要打印任何东西才能获得最终总和。
其中一个陈述exit(0);
和return(0);
是多余的。我建议使用return(0);
代替exit(0);
。