多个子进程+从流中读取

时间:2009-05-18 16:07:15

标签: c fork child-process external-sorting

参考我的上一个问题(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

提前感谢;)

4 个答案:

答案 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,则必须首先清理你一直在使用的流。