2

参考我的最后一个问题(多个子进程),我现在正在尝试使用多个子进程进行外部排序实现。

...
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);

但当然,由于 fscanf,这段代码会从 inputfile 输出相同的排序整数序列。例如,如果输入文件的开头包含 5 1 4,那么它会输出:

(第一个孩子) 1 4 5
(第二个孩子) 1 4 5

(有两个子进程).. 因为 fscanf 从输入流的开头开始读取整数。

我现在的问题是如何继续从前一个子进程离开的点开始读取数字?例如,如果输入文件包含 5 1 4 8 5 10,那么它可以输出:

(第 1 个孩子) 1 4 5

(第二个孩子) 5 8 10

提前致谢;)

4

4 回答 4

1

我会使用较低级别的 open() 和 read() 而不是等效的流,否则您将不得不担心将 stdio 缓冲区与底层文件描述符同步。请注意,您仍然会遇到读取完整数字的问题,因此您可能需要在进程之间进行一些同步。

作为替代方案,我建议使用单个进程来读取文件并将行的子集写入进行排序的子进程(使用 pipe()),然后将其写入另一个进行合并的进程。

于 2009-05-18T16:23:37.467 回答
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。

然后你必须弄清楚如何合并排序的结果。

于 2009-05-18T16:20:39.330 回答
0

如果您可以将整数存储为二进制。您可以让第一个线程读取它的块

fread(&arrayPartialData[j], sizeof(int), partialDataSize, fp);

第二个线程可以跳过已经读取的块(因为你知道每个块的大小)。然后您可以从那里开始阅读,而无需丢弃任何数据。

fseek(partialDataSize * threadNumber);

我还建议您使用线程,因为分叉非常昂贵。线程教程

于 2009-05-18T16:34:17.493 回答
0

您正在使用链接频道。

来自glibc 13.5.1(重点是我的)

来自单个打开的通道共享相同的文件位置;我们称它们为链接频道。当您使用 fdopen 从描述符创建流时,当您从具有 fileno 的流中获取描述符时,当您使用 dup 或 dup2 复制描述符时,以及在 fork 期间继承描述符时,会产生链接通道。

显然,您不能同时从两个流中执行 I/O。

如果您一直在使用流进行 I/O(或刚刚打开流),并且想要使用与其链接的另一个通道(流或描述符)进行 I/O,则必须首先清理您一直在使用的流。

于 2016-10-12T14:13:43.870 回答