Unix 使用fork()查找数字中的数字和
我正在编写一个小程序,它在命令行中获取一个数字,并使用fork()创建一个进程链,将数字相加。到目前为止,情况如下:Unix 使用fork()查找数字中的数字和,unix,fork,wait,system-calls,Unix,Fork,Wait,System Calls,我正在编写一个小程序,它在命令行中获取一个数字,并使用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 compi
#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;
}
在我添加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)
调用。据我所知,它迫使家长在继续之前等待所有的孩子。毫不奇怪,这会导致在最后一个创建的子项完成时首先打印实际的总和,并让其余的按顺序打印:[ 谢天谢地,这个程序实际上在这种情况下结束了。但是有没有一种方法可以使它在有实际总和的孩子返回并显示其结果时正确结束呢?我已经尝试过像直接调用
exit
(如您所见…),但这似乎是在与子进程不同的“领域”中运行的,并且不会在第一次打印后立即发生。使用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);
无需构建字符串并使用atoi
来获取字符的数值。(并且没有必要使用atoi
;而是使用strtol
)只需执行int i=argv[1][0]-“0”
(并验证argv[1][0]='0'
)将可执行名称硬编码到使用消息中是一种不好的做法;使用argv[0]
获取名称。用于(i=0;i
循环也不是一个好主意;它会计算每次迭代的长度,如果字符串很长,这可能会非常慢。在循环之外计算长度。
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
sum: 10
[nvj]@sun ~/313/sod> (12:15:24 02/10/13)
:: sum: 11
sum: 11
[hangs here...]