按顺序写入具有不同进程的同一文件

时间:2015-04-26 18:20:38

标签: c linux process

我正在开发基于UNIX的操作系统(Lubuntu 14.10。我有几个进程需要将消息打印到同一个文件和std输出。

当我将信息打印到屏幕上时,它按照我想要的方式按照出现的顺序工作。 E.g:

Process1_message1
Process2_message1
Process3_message1
Process1_message2
Process2_message2
Process3_message2
...

但是,当我检查输出文件时,它如下所示:

Process1_message1
Process1_message2
Process2_message1
Process2_message2
Process3_message1
Process3_message2
...

我使用fprintf(FILE *ptr, char *str)将消息写入文件。

注意:我在主流程中使用以下格式打开文件:

fptr=fopen("output.txt", "a");

其中fptr是全局FILE *

任何帮助将不胜感激。谢谢!

3 个答案:

答案 0 :(得分:2)

fprintf()无效。它很容易被转换成多次调用write()来实际写出数据,就像你发布的那样。您只需拨打fprintf()一次,并且会在write()内多次调用以实际将数据写入文件。

你需要使用open( filename, O_WRONLY | O_CREAT | O_APPEND, 0600 ),然后写这样的数据,以便确保你只调用write()一次,这保证是原子的:

ssize_t myprintf( int fd, const char *fmt, ... )
{
    char buffer[ 1024 ];
    ssize_t bytesWritten;
    va_list argp;
    va_start( argp, fmt );
    int bytes = vsnprintf( buffer, sizeof( buffer ), fmt, argp );
    if ( bytes < sizeof( buffer ) )
    {
        bytesWritten = write( fd, buffer, bytes );
    }
    // buffer was too small, get a bigger one
    else
    {
        char *bufptr = malloc( bytes + 1 );
        bytes = vsnprintf( bufptr, bytes + 1, fmp, argp );
        bytesWritten = write( fd, bufptr, bytes );
        free( bufptr );
    }

    return( bytesWritten );
}

答案 1 :(得分:2)

最有可能的问题是,文件输出是完全缓冲的,因此每个进程的输出都不会出现,直到流的标准I / O缓冲区(在该进程中)已满。

你可以通过设置行缓冲来充分解决它:

FILE *fptr = fopen("output.txt", "a");
if (fptr != 0)
{
    setvbuf(fptr, 0, _IOLBF, BUFSIZ);
    …code using fptr — including your fork() calls…
    fclose(fptr);
}

每次进程将一行写入缓冲区时,都会刷新它。如果输出行长于BUFSIZ,则可能会遇到问题;那么您可能希望将传递给setvbuf()的大小增加到您需要原子编写的最大行长度。

如果仍然不够好,或者您需要一次能够编写一组行,那么您必须使用{{3}中的文件描述符来寻求解决方案{&#39; s Andrew Henle。您可能希望查看answerO_SYNCO_DSYNC选项。

答案 2 :(得分:0)

当您写入终端(isatty(fptr) ---请参阅 isatty(3) ---返回true)时,刷新缓冲区在stdio中有所不同输出到文件。对于文件, stdio 输出仅在缓冲区填满时执行 write(2)系统调用,这会使所有消息一起显示(因为每个缓冲区都会刷新在退出时,它们填充一个单独的输出缓冲区)在ttys上,当缓冲区填满或当\n字符输出到缓冲区时,输出被刷新(作为对缓冲的妥协/非缓冲)

您可以在fflush(fptr);之后使用fprintf(fptr, ...);强制执行缓冲区刷新,或者甚至执行fflush(NULL);(在一次调用中刷新所有输出缓冲区)。

但是,要小心,因为写操作是控制调用的原子性(而不是fprintf调用)所以,如果你必须在一个fprintf调用中写几页输出,请准备好接受混乱的输出。