C:多进程stdio追加模式

时间:2012-01-22 11:07:59

标签: 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);
    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);
}

此代码以附加模式打开文件并附加200次字符串。 我设置了大小为100的buf,它可以包含完整的字符串。 然后我使用这个bash脚本创建了运行此代码的多个进程:

#!/bin/bash

gcc source.c
rm output.txt

for i in `seq 1 100`;
do
    ./a.out &
done

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

[ xx - [ xx - 7 - 012345678901234567890123456789 - 22545]

以后有些行

2 - 012345678901234567890123456789 - 22589]

看起来写入因调用rand函数而中断。

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

提前致谢!

2 个答案:

答案 0 :(得分:2)

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

引用POSIX write()

  

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

(在 Rationale 部分的末尾。)

答案 1 :(得分:1)

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

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

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