【问题标题】:unexpected EOF when reading a file in multi process environment在多进程环境中读取文件时出现意外 EOF
【发布时间】:2016-10-06 16:56:55
【问题描述】:

我有一个文件 instructions.txt(由文件指针 fp 表示),它由 12 行组成(每行包含字节 ls\nps\n 交替)。

最初主进程以读取模式打开文件,创建并初始化共享内存区域mem,并使用fork()创建另外11个进程。

12 个进程中的每一个都应该从文件中读取一行并执行该指令。在进入最外层while块之前,在所有进程中调用ftell(fp)返回0。

问题是,进入最外层if块的第一个进程使用fgets读取一行后,在其他进程中调用ftell返回36(文件大小为12x3 = 36字节)。 ftell 在执行 fgets first 的进程中仍然返回 3(第一行结束)。

所以下次任何进程调用fgets时,它都会返回一个EOF

共享内存区域mem 用作“数组”,其中第 1 到第 12 个元素包含 12 个进程的 PID,第 0 个元素用作索引来决定哪个进程将进入最外层的if 块。

这是导致问题的 sn-p -

while(mem[0] > 0)
{
    printf("(%u) pos = %ld\n", curr_pid, ftell(fp));

    // only the process whose PID matches the value in 
    // mem[mem[0]] can enter
    if(curr_pid == mem[mem[0]])
    {
        printf("\n\nprocess %u enters CS\n", curr_pid);
        char instr[100];
        printf("pos before read = %ld\n", ftell(fp));
        if(fgets(instr, 100, fp) == NULL)
        {
            perror("fgets error or EOF");
            //return 1;
        }
        printf("pos after read = %ld\n", ftell(fp));
        instr[strlen(instr)-1] = 0;
        printf("process %u executing command: %s, size = %lu\n", curr_pid, instr, strlen(instr));

        /* execute instruction */
        char *args[] = {instr, NULL};
        pid_t exec_pid = fork();
        if(exec_pid == -1)
        {
            perror("fork error");
        }
        else if(exec_pid == 0) // child execs
        {
            execvp(instr, args);
            perror("execvp error");
            return 1;
        }
        printf("process %u leaving CS\n", curr_pid);
        sleep(5);
        mem[0]--; // alow next process to enter and read
    }
    sleep(1);
}

这里

  • (FILE *) fp 是指向instructions.txt 文件的文件指针

  • (int *) mem 是附加到所有 12 个进程的共享内存

  • mem[0] 是在mem 中找到要选择进入if 块的进程的PID(即mem[mem[0]] 包含PID mem[0]th 进程

  • (pid_t) curr_pid为每个进程存储自己的PID

本质上,只有一个进程进入最外层的if 块,而其他进程通过循环“等待”直到轮到它们

【问题讨论】:

    标签: c linux file-io synchronization


    【解决方案1】:

    您的进程都有与内核维护的相同打开文件描述相关联的流。这些流的缓冲区属于进程,但文件偏移量属于底层打开文件描述。

    每当一个进程从一个没有缓冲数据的流中读取数据时,它很可能会向缓冲区中读取更多的数据,而不是它最终立即使用的数据。这就是你的情况。第一个读取的进程将文件的所有 36 个字节读取到其流缓冲区的副本中,将底层文件偏移量推进到文件末尾。之后尝试从流中读取的进程不共享第一个流缓冲区;他们所看到的只是(共享)文件偏移量位于文件末尾。

    如果您希望多个进程协同读取同一个文件,那么您需要考虑到这一点。我至少可以看到两种机制:

    1. 在您的共享内存段中,您还维护了迄今为止消耗的字节数的计数。每个进程使用它在尝试读取之前将fseek() 执行到适当的位置。

    2. 您使用低级 I/O 和文件描述符(open()read())而不是流 I/O。就您执行任何缓冲而言,您将缓冲区保留在共享内存中。

    还要注意,您需要某种形式的同步来确保每个进程都能看到其他进程执行的对共享内存的写入。您可以通过创建和正确使用进程共享的互斥锁和条件变量来提供这一点摆脱浪费的自旋锁。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-21
      • 2022-08-16
      • 2013-05-21
      • 1970-01-01
      • 1970-01-01
      • 2022-07-08
      • 2018-04-18
      相关资源
      最近更新 更多