两个进程写入同一个文件

Two processes writing on the same file

我知道这是灾难的根源。我实际上使用共享变量让它工作。

但这是作业,老师肯定希望我们把许多进程使用不同的文件指针写入同一个文件。我一整天都在尝试,但收效甚微,但我就是找不到失败的原因。

我已经通过以下方式解决了这个问题:

#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

这意味着,出于某种原因,只写入了最后一个值。

我一直在为此苦思冥想,但我就是找不到问题所在...有人可以帮帮我吗?

问题是由于 fopen("./parciais.txt", "w") :
"w" : "Creates an empty file for writing. If a file with the same name already exists, its content is erased and the file is considered as a new empty file."
试试 "a"!
("Appends to a file. Writing operations, append data at the end of the file. The file is created if it does not exist.")

正如另一个答案中提到的, "a" 参数也不够。该文件必须创建一次,因此在主进程中创建,然后以 "r+b" 模式访问以使 fseek 正常工作!

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

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

  • 如果它尚不存在(或者我想你至少想要这个),则创建它
  • 不是 t运行如果它确实已经存在
  • 你可以给它写信
  • 从当前文件偏移量开始写入,而不是自动转到文件的当前末尾
  • 该文件是二进制文件,不受任何类型的字符转换或写入时尾部 t运行阳离子

不幸的是,没有提供所有这些的标准模式:各种 r 模式要求文件已经存在,w 模式 t运行cate 文件如果它确实已经存在,并且 a 模式将所有写入定向到文件的当前末尾,而不管流的当前偏移量如何。如果您可以假设该文件已经存在,那么模式 "r+b"(也可以拼写为 "rb+")具有所有需要的特征,但如果文件不存在则创建该文件:

    aux = fopen("./parciais.txt", "r+b");

这也允许读取,但仅仅因为您 可以 从文件中读取并不意味着您必须这样做。此外,在符合 Linux 和 POSIX 的系统上,二进制文件和文本文件之间没有区别,因此如果您确信您的程序需要 [=54],则可以省略 b =] 仅在 POSIX 系统上。您正在使用 fork() 表明此条件可能适用于您。

如果您也必须提供创建文件的功能,则在程序的最开始打开它一次,使用 wa 模式中的任何一种,具体取决于您是否想要t运行编辑文件,然后立即再次关闭:

FILE *aux = fopen("./parciais.txt", "a");
if (aux) {
    fclose(aux);
} else {
    // handle error ...
}