C:多进程stdio追加模式

C:多进程stdio追加模式,c,append,stdio,logfiles,multiprocess,C,Append,Stdio,Logfiles,Multiprocess,我用C编写了这段代码: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> void random_seed(){ struct timeval tim; gettimeofday(&tim, NULL); double t1=tim.tv_sec+(tim.tv_usec/1000000.0); sran

我用C编写了这段代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

void random_seed(){
    struct timeval tim;
    gettimeofday(&tim, NULL);
    double t1=tim.tv_sec+(tim.tv_usec/1000000.0);
    srand (t1);
}

void main(){
    FILE *f;
    int i;
    int size=100;
    char *buf=(char*)malloc(size);

    f = fopen("output.txt", "a");
    setvbuf (f, buf, _IOFBF, size);
    random_seed();

    for(i=0; i<200; i++){
          fprintf(f, "[ xx - %d - 012345678901234567890123456789 - %d]\n", rand()%10, getpid());
          fflush(f);
    }

    fclose(f);
    free(buf);
}
我希望在输出中字符串永远不会混淆,因为我读到当使用O_APPEND标志打开文件时,文件偏移量将在每次写入之前设置为文件末尾,并且我使用的是完全缓冲的流,但我得到的每个进程的第一行是混合的,如下所示:

[ xx - [ xx - 7 - 012345678901234567890123456789 - 22545]
稍后还有几行

2 - 012345678901234567890123456789 - 22589]
调用rand函数时,写入操作似乎被中断

那么…为什么会出现这些线条? 防止这种情况的唯一方法是使用文件锁定…即使我只使用附加模式


提前谢谢

您需要自己实现某种形式的并发控制,POSIX不保证来自多个进程的并发写入。对于管道,您可以得到一些保证,但对于从不同进程写入的常规文件,则不能得到保证

引述:

POSIX.1-2008的本卷未指定多个进程并发写入文件的行为应用程序应该使用某种形式的并发控制。


(在基本原理部分的末尾。)

以完全缓冲模式打开文件。这意味着输出的每一行首先进入缓冲区,当缓冲区溢出时,它将被刷新到文件中,而不管它是否包含不完整的行。这导致并发写入同一文件的不同进程的输出块被交错

一个简单的修复方法是以行缓冲模式打开文件,这样就可以在每一行上刷新缓冲区。只需确保缓冲区大小至少与最长的行一样大,否则它将最终写入不完整的行。缓冲区通常通过单个
write()
系统调用刷新,因此来自不同进程的行不会相互交错


虽然不能保证
write()
系统调用对于不同的文件系统是原子的,但它通常会按预期工作,因为
write()
在继续之前通常会使用互斥锁锁定内核中的文件描述符。

感谢链接!在同一页中写道:“如果设置了文件状态标志的O_APPEND标志,则应在每次写入之前将文件偏移量设置到文件的末尾,并且在更改文件偏移量和写入操作之间不应发生干涉文件修改操作。”我刚刚看到,当我将缓冲区大小设置为大于128的值时,它会像我预期的那样工作。。。当我使用小于128时,看起来setvbuf的结果不正确。您应该了解到,在更改文件偏移量和写入操作之间,将发生as
干预文件修改操作。进程中存在/可能存在锁定,以防止多个线程同时写入。在进程之间没有这样的保证。另一个进程可能会在文件偏移量更改和写入之间执行操作。请重复您的第二条评论:它无法按预期工作。您启动它时,它似乎起作用了。不能保证它能与任何缓冲区大小一起工作。(但如果您完全禁用缓冲,它应该经常工作。)#include#include int main(void){int size=128;char*buf=malloc(size);setvbuf(stdout,buf,_IOFBF,size);printf(“5秒过去了吗?\n”);sleep(5)}幸运的是,有
\u IOLBF
使得
fush()变得不必要。代码中的行越少,错误越难隐藏。
\u IOLBF
不能为我修复它,只有
\u IONBF
/*没有缓冲。*/做(注意:使用与OP相同的程序,缓冲区为100字节)@howaboutsynergy您可能想用您的代码发布另一个问题。@MaximeGroushkin代码已在OP中可用(即在问题中),我只是简单地用
\u IOLBF
替换了
\u IOLBF
,正如您的回答:
一个简单的解决方法是以行缓冲模式打开文件,以便在每一行上刷新缓冲区。只需确保缓冲区大小至少与最长的行一样大,否则它将最终写入不完整的行。
。我只是指出,对我来说,这显然不是真的。我注意到
libio/fileops.c
有一条评论说:
我们用来刷新所有行缓冲流。这真的不是任何标准所要求的。
如果缓冲区大小>=,我不会得到3种模式中的任何一种模式的交织。我将探究原因,但乍一看,
libio/fileops.c
只显示了一次写入的
128
,但我需要时间来理解逻辑<代码>/*尝试保持对齐:写入完整数量的块*/
2 - 012345678901234567890123456789 - 22589]