两个进程在同一个文件上写入

时间:2019-04-10 20:39:54

标签: c fork fwrite

我知道这是灾难的秘诀。实际上,我使用共享变量来使其工作。

但这是家庭作业,老师肯定希望我们投入许多使用不同文件指针来写入同一文件的进程。我一整天都在尝试,但收效甚微,但我找不到为什么失败了。

我已经按照以下方式解决了这个问题:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    int status;
    int process_count = 0;

    do
    {
        int from = (n / np) * (process_count) + 1;
        int to = (n / np) * (process_count + 1);

        if (fork() == 0)
        {
            FILE *aux;
            aux = fopen("./parciais.txt", "w");
            fseek(aux, sizeof(int) * process_count, SEEK_SET);

            int sum = 0;
            int i = from;
            while (i <= to)
            {
                int square = i * i;
                sum += square;
                i++;
            }

            long int where_am_i = ftell(aux);
            printf("I am process %i writing %i on byte: %li\n", process_count, sum, where_am_i);

            fwrite(&sum, sizeof(int), 1, aux);
            fclose(aux);
            exit(1);
        }
        else
        {
            wait(&status);
            process_count++;
        }
    } while (process_count < np);

    FILE *aux;
    aux = fopen("./parciais.txt", "r");

    int sum;
    for (int i = 0; i <= np - 1; i++)
    {

        fseek(aux, sizeof(int) * i, SEEK_SET);
        long int where_am_i = ftell(aux);

        int read;
        fread(&read, sizeof(int), 1, aux);
        printf("I am reading %i at byte: %li\n", read, where_am_i);

        sum += read;
    }
}

我希望输出结果如下:

I am process 0 writing 98021 on byte: 0
I am process 1 writing 677369 on byte: 4
I am process 2 writing 1911310 on byte: 8
I am reading 98021 at byte: 0
I am reading 677369 at byte: 4
I am reading 1911310 at byte: 8

但是我得到了

I am process 0 writing 98021 on byte: 0
I am process 1 writing 677369 on byte: 4
I am process 2 writing 1911310 on byte: 8
I am reading 0 at byte: 0
I am reading 0 at byte: 4
I am reading 1911310 at byte: 8

这意味着由于某种原因,仅写入最后一个值。

我一直在把头撞在墙上,我只是找不到在哪儿……有人可以帮我吗?

2 个答案:

答案 0 :(得分:1)

问题归因于fopen("./parciais.txt", "w")
“ w”:“创建一个用于写入的空文件。如果已经存在同名文件,则其内容将被删除,并且该文件将被视为新的空文件。”
尝试使用“ a”代替!
(“附加到文件。写入操作,将数据附加在文件末尾。如果文件不存在,则创建该文件。”)

如另一个答案中所述,“ a”自变量也不足够。该文件必须在主进程中创建一次,然后才能在“ r + b”模式下访问,以便fseek正常工作!

答案 1 :(得分:1)

@ B.Go已经回答了,主要问题是您正在使用模式"w"打开文件,如果文件已经存在,则将其截断为零长度。每个子进程都会这样做,破坏了前一个进程编写的内容。

您想要文件的这种行为组合:

  • 如果尚不存在,则创建它(或者我想至少要这样)
  • 如果 已经存在,则打开时被截断
  • 您可以写信
  • 写入从当前文件偏移开始,而不是自动转到文件的当前结尾
  • 文件为二进制文件,写入文件时不进行任何字符转换或尾部截断

不幸的是,没有提供所有功能的标准模式:各种r模式要求文件已经存在,w模式会截断文件,如果文件已经存在,{ {1}}模式将所有写入均定向到文件的当前末尾,而与流的当前偏移量无关。如果可以假设文件已经存在,则模式a(也可以拼写为"r+b")具有所有所需的特征,但不存在则创建文件:

"rb+"

这也允许读取,但是仅仅因为您可以从文件中读取并不意味着您必须这样做。此外,在Linux和POSIX兼容系统上,二进制文件和文本文件之间没有区别,因此,如果您确信程序仅需要在POSIX系统上运行,则可以省略 aux = fopen("./parciais.txt", "r+b"); 。您正在使用b表示此条件可能适用于您。

如果还必须提供创建文件的权限,请根据是否要截断文件名,使用任何一种fork()w模式在程序的开头将其打开一次。文件,然后立即将其再次关闭:

a