用于多个流程的管道

目前正在做一些功课,并且很难过。 目标是生成100,000个数字并将它们全部加在一起,方法是将工作分成10个进程(每个10,000个数字)

我想我已经想出了如何分叉进程(希望如此),但是使用Pipe()来传递每个子进程的小计不起作用……下面的程序为每个子进程返回44901,为运行总计返回449010。

我努力奋斗但我觉得这很简单,我应该能够理解。

main() { int i; pid_t pid; int status = 0; int fd[2]; int runningTotal = 0; pipe(fd); int t; int r; for (i = 0; i < 10; i++) { pid = fork(); if (pid == 0){ close(fd[0]); t = ChildProcess(); write(fd[1], &t, sizeof(t)); exit(0); } close(fd[1]); read(fd[0], &r, sizeof(r)); runningTotal = runningTotal + r; wait(&status); } printf("%i\n", runningTotal); } int ChildProcess() { int i; int total = 0; int r = 0; for (i = 0; i < 10000; i++) { r = rand() % 10; // 0 to 10 total = total + r; } printf("%i\n", total); return total; } 

通常,人们会为每个孩子使用单独的管道,否则父母不可能知道它所读取的数据来自哪个过程。 我不认为在这种特殊情况下这是一个很大的问题,因为在这里,你实际上并不在意。 虽然它仍然让我有点畏缩,但我认为你确实可以通过一个管道来完成这项特殊任务。

事实上,我认为你的问题根本就不在管道上。 它与rand() 。 所有子进程计算完全相同的(伪)随机数序列,因为它们都使用相同的(默认)种子。 如果要生成不同的数字序列,则需要在每个子进程中调用srand()在每个子进程中给出不同的种子。 rand()将生成的数字序列完全由它开始的种子决定。

还要注意,如果系统的随机数生成器完全没有任何好处,那么各个进程计算的所有总和应该彼此非常接近,并且与您报告的结果非常接近。 这是统计中的中心极限定理的结果,但您可以将其视为平均较小的平衡的较大结果。 计算余数mod 10可能会产生轻微偏差。

初步诊断

如果您担心孩子们都生成相同的值,那么问题是他们都使用相同的随机序列,因为您不会在任何地方调用srand() 。 你需要为每个孩子打电话一次,每个孩子都有一个不同的种子。

它不是100%可靠,但你可以通过srand(time(0) + getpid());逃脱srand(time(0) + getpid()); 在每个孩子 – 甚至只是getpid()因为这些值保证不同。

 #include  #include  #include  #include  int ChildProcess(void) { int total = 0; srand(time(0) + getpid()); for (int i = 0; i < 10000; i++) { int r = rand() % 10; // 0 to 9 (not 10). total = total + r; } printf("%i\n", total); return total; } 

进一步审查

实际上,经过仔细研究,还有另一个问题。 父进程在分叉第一个子进程后关闭管道的写端,因此后续子进程没有可用的文件描述符。 读取值始终是第一个孩子的值。 所以,你需要做更认真的工作。

 int main(void) { int fd[2]; pipe(fd); // Missing error check for (int i = 0; i < 10; i++) { pid_t pid = fork(); if (pid == 0){ close(fd[0]); int t = ChildProcess(); write(fd[1], &t, sizeof(t)); // Missing error check? exit(0); } // Print PID here? Error check? } close(fd[1]); int r; int runningTotal = 0; while (read(fd[0], &r, sizeof(r)) > 0) // Debugging opportunities here runningTotal = runningTotal + r; while (wait(0) > 0) // Lots of debugging opportunities here ; printf("%i\n", runningTotal); return 0; } 

鉴于此代码:(摘自已发布的代码)

 for (i = 0; i < 10; i++) { pid = fork(); if (pid == 0){ close(fd[0]); t = ChildProcess(); write(fd[1], &t, sizeof(t)); exit(0); } close(fd[1]); read(fd[0], &r, sizeof(r)); runningTotal = runningTotal + r; wait(&status); } 

有序列问题。

当父进程在循环的第一次迭代期间关闭fd [1]时,该文件描述符在下一次循环迭代时不会再“神奇地”打开。

在循环中,父代码需要检查read()调用的返回值,以确保操作成功。 (在循环的第一次迭代后,它可能没有成功,因此变量'r'将保持不变。