这是前两个问题的更清晰的最终版本(丑陋的代码;由我删除)。
我使用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);
}
}
}
输出:
Will use 1 child process(es).
Parent(5497): Sending file position to child
Child(5498): Recieved position: 0
▒▒Child(5498): Sent 454019 to parent. //**yes this weird mark shows up**
Parent(5498): Sending file position to child
//hangs
Will use 2 child process(es).
Parent(5898): Sending file position to child
Child(5899): Recieved position: 0
▒|Child(5899): Sent 228601 to parent.
Parent(5899): Sending file position to child
//hangs
Will use 4 child process(es).
Parent(5904): Sending file position to child
Child(5905): Recieved position: 0
▒Child(5905): Sent 118304 to parent.
Parent(5905): Sending file position to child
//hangs
该代码适用于一个孩子,我可以看到总和,但它挂起,父母从不承认孩子的输入。因此,如果我使用2个孩子,我只能看到1-500行的总和。如果我使用4个孩子,我只能看到1-250行的总和。
在第一个孩子将结果发回给父母后,我在做什么来挂断我的课程?
我的代码是否允许孩子同时工作?
感谢您的帮助。
- 汤姆
答案 0 :(得分:3)
您没有初始化所有管道。为简单起见,假设您有四个孩子。
然后在这里,您为总共8个管道,16个文件描述符分配空间:
int fd[2*numchild][2]; //parent+child pipe
到目前为止一切顺利;父母需要一个专用的管道来写给孩子,反之亦然,孩子要写给父母。
但是,您没有正确初始化您的管道:
for (i=0; i<numchild; i++)
{
pipe(fd[i]);
}
只初始化8个文件描述符,而不是16个。你需要创建for( i = 0; i < 2*numchild; 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]
然后,因为您没有正确初始化您的管道,您正在阅读并写入错误的管道;具体来说,如果你有幸将fd
初始化为全零,那么你可能正在阅读和写入标准输出。
这解释了为什么它会死锁 - 你没有读到你打算写的管道。这就解释了为什么您在标准输出上获得奇怪的输出:您将fpos
写入错误的文件描述符,因为fd
未完全初始化;您正在将fpos
写入文件描述符0
,又称标准输出。