C 使用Fork()和Pipe()将文件拆分为多个子进程求和

C 使用Fork()和Pipe()将文件拆分为多个子进程求和,c,pipe,fork,C,Pipe,Fork,这是前两个问题的更清晰的最终版本(丑陋的代码;由我删除) 我使用pipe()和fork()对子进程中的文件内容求和。为此,我根据子对象的数量将文件平均分割: 文件中的1000行=>2个子进程=>1-500行的第一个子进程和;第二个子项合计第501-1000行=>将总计发送回父项,以对其每个总计进行合计。这样,就可以找到整个文件的总数 这是我的密码: #include <stdio.h> #include <stdlib.h> #include <unistd.h&

这是前两个问题的更清晰的最终版本(丑陋的代码;由我删除)

我使用
pipe()
fork()
对子进程中的文件内容求和。为此,我根据子对象的数量将文件平均分割:

文件中的1000行=>2个子进程=>1-500行的第一个子进程和;第二个子项合计第501-1000行=>将总计发送回父项,以对其每个总计进行合计。这样,就可以找到整个文件的总数


这是我的密码:

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

int main(int argc, char *argv[])
{
int numchild;
int fd[2*numchild][2]; //parent+child pipe
int i, j, len, fpos=0, val, count=0, total=0;
pid_t pid;
int nums = 1000;
FILE * file;

printf("How many children to use: ");
scanf("%d", &numchild);
printf("\nWill use %d child process(es).\n", numchild);

// create all pipes
for (i=0; i<numchild; i++)
{
    pipe(fd[i]);
}

for (i=0; i<numchild; i++)
{
    if((pid = fork()) == 0) // child process
    {
        pid = getpid();

        // read from parent
        len = read(fd[i][0], &fpos, sizeof(fpos));
        if (len > 0)
        {
            file = fopen("file1.dat", "r");
            fseek (file, fpos, SEEK_SET);
            count = 0;
            total = 0;

            printf("Child(%d): Recieved position: %d\n", pid, fpos);

            // read from file starting at fpos
            // add values read to a total value
            while (count < (nums/numchild))
            {
                fscanf(file, "%i", &val);
                total += val;
                count++;
            }
            //write to parent
            write(fd[i+numchild][1], &total, sizeof(total));
            printf("Child(%d): Sent %d to parent.\n", pid, total);
        }
        else
        {
            printf("Child(%d): Error with len\n", pid);
        }

        _exit;
    }

    // parent process
    pid = getpid();

    fpos = ((i*nums*5)/numchild); // 5 is the offset of the file values

    // write to child process
    printf("Parent(%d): Sending file position to child\n", pid);
    write(fd[i][1], &fpos, sizeof(fpos));

    // wait for child responce
    len = read(fd[i+numchild][0], &total, sizeof(total));
    if (len > 0)
    {
        printf("Parent(%d): Recieved %d from child.\n", pid, total);
        total += total;
        printf("Parent(%d): Total: %d\n", pid, total);
    }
    else
    {
        printf("Parent(%d): Error with len\n", pid);
    }
}
}


代码对一个我可以看到求和的孩子来说效果很好,但是它挂起了,并且家长从未确认来自孩子的输入。因此,如果我使用2个子项,我只能看到第1-500行的总和。如果我使用4个子项,我只能看到第1-250行的总和

在第一个孩子将结果发送回家长后,我要做什么来挂断我的程序

我的代码允许孩子们同时工作吗


谢谢你的帮助


-Tom

您没有初始化所有管道。为了简单起见,假设你有四个孩子

然后在这里,您将为总共8个管道、16个文件描述符分配空间:

int fd[2*numchild][2]; //parent+child pipe
到目前为止还不错;父级需要专用管道向子级写入,反之亦然,子级需要专用管道向父级写入

但是,您没有正确初始化管道:

for (i=0; i<numchild; i++)
{
    pipe(fd[i]);
}
然后,因为没有正确初始化管道,所以读写错误的管道;具体来说,如果您有幸将
fd
初始化为全零,那么您可能正在读写标准输出


这就解释了为什么它会死锁——你没有读到你打算写的管道。这就解释了为什么在standard out上会有奇怪的输出:您将
FPO
写入了错误的文件描述符,因为
fd
没有完全初始化;您正在将
fpo
写入文件描述符
0
,即标准输出。

您没有初始化所有管道。为了简单起见,假设你有四个孩子

然后在这里,您将为总共8个管道、16个文件描述符分配空间:

int fd[2*numchild][2]; //parent+child pipe
到目前为止还不错;父级需要专用管道向子级写入,反之亦然,子级需要专用管道向父级写入

但是,您没有正确初始化管道:

for (i=0; i<numchild; i++)
{
    pipe(fd[i]);
}
然后,因为没有正确初始化管道,所以读写错误的管道;具体来说,如果您有幸将
fd
初始化为全零,那么您可能正在读写标准输出


这就解释了为什么它会死锁——你没有读到你打算写的管道。这就解释了为什么在standard out上会有奇怪的输出:您将
FPO
写入了错误的文件描述符,因为
fd
没有完全初始化;您正在将
fpo
写入文件描述符
0
,又名,标准输出。

由于所有这些复杂性,它很可能比使用一个过程慢得多-限制因素是读取数据的速度file@EdHeal我们的目标是了解在读取非常大的文件(1000行、10000行、100000行、1000000行)时,我的程序运行速度会受到怎样的影响,等等。为什么在每个子循环结束时调用
wait(NULL)
?这将导致循环在启动子N+1之前等待子N。点不是多重处理吗?为什么父循环的每子循环乘以2<代码>用于(i=0;i@antiduh我之所以这样做,最初是因为每个子进程有两个管道(父到子,子到父).这一点已被改变。由于所有这些复杂性,它很可能比使用一个进程慢得多-限制因素是读取数据的速度file@EdHeal我们的目标是了解当从非常大的文件(1000行、10000行、100000行、1000000行等)读取时,我的程序运行速度是如何受到影响的u在每个子循环结束时调用
wait(NULL)
?这将导致循环在开始子循环N+1之前等待子循环N。该点不是多重处理吗?为什么父循环的每个子循环乘以2?
for(i=0;i@antiduh我最初这样做是因为每个子进程有两个管道(父母对子女,子女对父母)。这已经改变了。谢谢你的解释。它现在运行得更好了,但我仍然遇到问题。一个问题是,即使只有一个孩子要写,我的父母仍然试图给另一个孩子写。然后,家长会得到总数并挂起。另一个问题是,当我试图在末尾添加一些代码时
alltotal+=total
我需要初始化一个
int-alltotal;
int-alltotal;
很好,但是当我设置为
int-alltotal=0;
时,我得到了一个
分段错误(堆芯转储)
。你知道这些错误可能来自何处吗?我将在原始帖子中更新我的代码。@Tawm-我们修复了一个问题-管道的初始化。另一个问题应该是一个全新的问题,否则,它会变得太混乱,无法尝试跟踪每个问题和答案。因此我会将你的问题编辑回原来的状态,然后重试用你的新问题引出一个新问题。只是为了开始:你看过核心文件了吗?确保你在新问题中发布了你对核心文件的分析。我将开始一个新问题。但在此之前,你说的核心文件是什么意思?你说你得到了以下输出:
分段错误(核心转储)
。这意味着您的程序做了非法的事情,操作系统通过将程序的运行状态写入核心文件来响应。您可以使用gdb之类的调试器分析此文件,从而找出程序崩溃的原因。
for (i=0; i<numchild; i++)
{
    pipe(fd[i]);
}
fd[0][0]
fd[0][1]
fd[1][0]
fd[1][1]
fd[2][0]
fd[2][1]
fd[3][0]
fd[3][1]