参考我的上一个问题(Multiple child process),我现在尝试使用多个子进程进行外部排序实现。
...
fp = fopen(pathname, "r"); // open inputfile in r mode
fgets(trash, 10, fp); // ignore first line
for (i=0; i<numberOfProcess; ++i) {
#ifdef DBG
fprintf(stderr, "\nDBG: Calling fork()\n");
#endif
if ((pids[i] = fork()) < 0) {
perror("fork error");
exit(EXIT_FAILURE);
} else if (pids[i] == 0) { // Child Code
if (numbersToSort % numberOfProcess == 0) { // 16 % 4 = 0
partialDataSize = numbersToSort / numberOfProcess;
for (j=0; j<partialDataSize; j++) {
fscanf(fp, "%d", &arrayPartialData[j]);
qsort(arrayPartialData, partialDataSize, sizeof(int), (void *)comp_num);
//printf("%d\n", arrayPartialData[j]);
// TODO: qsort data until partialDataSize
}
}
printf("pid: %d child process %d outputs: ", getpid(), pids[i]);
printArray(arrayPartialData, partialDataSize);
//break;
exit(0);
}
}
/* Wait for children to exit. */
while (numberOfProcess > 0) {
pid = wait(&status);
--numberOfProcess;
}
fclose(fp);
但是当然这个代码从inputfile输出相同的排序整数序列,因为fscanf ..例如,如果输入文件的开头包含5 1 4,那么它输出:
(第1个孩子)1 4 5
(第2个孩子)1 4 5
(有两个子进程)..因为fscanf从输入流的开头开始读取整数。
我现在的问题是如何继续从上一个子进程离开的点开始读取数字?例如,如果输入文件包含5 1 4 8 5 10,那么它可以输出:
(第1个孩子)1 4 5
(第二个孩子)5 8 10
提前感谢;)
答案 0 :(得分:1)
我使用较低级别的open()和read()而不是等效的流,否则您将不得不担心将stdio缓冲区与基础文件描述符同步。请注意,读取完整数字时仍然存在问题,因此您可能需要在这些过程之间进行一些同步。
作为替代方案,我建议单个进程读取文件并将行的子集写入进行排序的子进程(使用pipe()),然后将它们写入另一个进行合并的进程。
答案 1 :(得分:0)
如果您正在使用fscanf,那么您唯一能做的就是让每个进程都读取并丢弃数字,直到找到它应该处理的数字。在你的情况下丢弃i * partialdatasize数字。
所以,例如5 7 3 1 4 8 5 10 2你可能有 5 7 3
1 4 8
5 10 2
将分类给出
3 5 7
1 4 8
2 5 10。
然后你必须弄清楚如何合并排序的结果。
答案 2 :(得分:0)
如果可以将整数存储为二进制。你可以让第一个线程读取它的块
fread(&arrayPartialData[j], sizeof(int), partialDataSize, fp);
比第二个线程可以跳过已经读取的块(因为你知道每个块的大小)。然后你可以从那里开始阅读,而不需要丢弃任何数据。
fseek(partialDataSize * threadNumber);
我还建议你使用线程,因为分叉是非常昂贵的。 threads tutorial
答案 3 :(得分:0)
您正在使用关联渠道。
来自 glibc 13.5.1 (强调是我的)
来自单个开口的频道共享相同的文件位置;我们称之为关联渠道。当您使用fdopen从描述符创建流时,当您从具有fileno的流中获取描述符时,当您使用dup或dup2复制描述符时,以及在fork期间继承描述符时,会导致链接通道。
显然,你不能同时从两个流中进行I / O.
如果您一直在为I / O使用流(或者刚刚打开了流),并且您希望使用链接到它的其他通道(流或描述符)进行I / O,则必须首先清理你一直在使用的流。