【问题标题】:Multiple child process + reading from a stream多个子进程+从流中读取
【发布时间】:2010-10-27 01:58:47
【问题描述】:

关于我的最后一个问题 (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);

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

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

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

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

(第一个孩子)1 4 5

(第二个孩子)5 8 10

提前致谢;)

【问题讨论】:

  • 如果他们必须顺序读取文件,他们将如何并行执行?这似乎不会让你的程序更快。
  • 我的目标不是并行执行进程..我只是试图用一个子进程排序的一部分和另一个子进程排序的另一部分等等..最后,父级将合并结果..
  • 在你分叉孩子之前尝试将文件读入内存,然后让每个孩子足够聪明,知道它拥有更大数组的哪一部分。

标签: c fork child-process external-sorting


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    如果你使用 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。

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

    【讨论】:

      【解决方案3】:

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

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

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

      fseek(partialDataSize * threadNumber);
      

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

      【讨论】:

        【解决方案4】:

        您正在使用链接频道。

        来自 glibc 13.5.1(重点是我的)

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

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

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

        【讨论】:

          猜你喜欢
          • 2019-05-26
          • 2021-10-13
          • 1970-01-01
          • 1970-01-01
          • 2016-03-26
          • 2012-10-06
          • 1970-01-01
          • 1970-01-01
          • 2015-12-27
          相关资源
          最近更新 更多