【问题标题】:possibilty of locking for multi processes writing their log in a file concurrently锁定多个进程同时将其日志写入文件的可能性
【发布时间】:2019-11-08 14:18:17
【问题描述】:

我发现了在多进程环境中使用 fputs 和 fflush 的一些错误。 所以我编写了如下的简单代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "windows.h"
#define FILENAME "test.txt"

int main(int argc , char *argv[]) 
{ 
    FILE *file; 
    file = fopen(FILENAME , "a"); 

    char buf[10240 + 100];
    int pid = GetCurrentProcessId();
    char buf_pid[20];
    itoa(pid, buf_pid, 10);

    int ii = 0;
    while(ii < 10000)
    {
        time_t     now = time(0);
        struct tm  tstruct;
        char       tt[80];
        tstruct = *localtime(&now);
        strftime(tt, sizeof(tt), "%Y/%m/%d %X", &tstruct);

        strcpy(buf, tt); 
        strcpy(buf + strlen(tt), " ");
        strcpy(buf + strlen(tt) + 1, buf_pid);
        strcpy(buf + strlen(tt) + strlen(buf_pid), " ");

        int len = strlen(tt) + strlen(buf_pid) + 1;

        int a = rand()%10240;
        char temp;
        for(int i=0;i<a;i++)
        {
            temp = 'a' + rand()%25;
            memset(buf + len, temp, 1);
            len++;
        }
        buf[len++] = '\n';
        buf[len++] = 0;

        //Sleep(1);
        printf("%d %s %d %d\n", ii, tt, pid, a);
        fputs(buf, file);
        fflush(file);**

        ii++;
    }

我运行了一些批处理文件,如下所示:

start filewrite.exe
start filewrite.exe
start filewrite.exe
start filewrite.exe
start filewrite.exe
start filewrite.exe
start filewrite.exe
start filewrite.exe
start filewrite.exe
start filewrite.exe
start filewrite.exe
start filewrite.exe
start filewrite.exe
start filewrite.exe
start filewrite.exe
start filewrite.exe
start filewrite.exe
start filewrite.exe
start filewrite.exe
start filewrite.exe

当然,结果如下所示。

2019/11/08 22:57:14 261 rjatydimofugclqurclqecdrhvqsuwbvntmryktdl..
2019/11/08 22:57:14 261 ixoqldswtmhmjxqedqkprngproxvfpeuagbsxexje..
2019/11/08 22:57:14 261 skrhmutgpnkpwopudobptikjrfogdeairwyglcrqe..
2019/11/08 22:57:14 261 sqytmhtrnqkrtnfigwgcvvacgklmcjxinhehaqish..
2019/11/08 22:57:14 261 pvdvsfksuonldbwstvgflwjpecfymtfdrsnxlqqod..
2019/11/08 22:57:14 261 oqatxghvkhhjyvgnlymcjapedmpdakuuphbxnuqtd..
2019/11/08 22:57:14 261 ufrjkikbwvlvjejhpnndyebmgfjbmwvldsrlephow..
..

没有明确的互斥体,所以 fputs 和 fflush 不是自动的。 我知道 fputs 是用它在操作系统内核中的句柄将文本写入文件的缓冲区 fflush 是将缓冲区刷新到磁盘中。虽然没有同步对象,但访问每个缓冲区或刷新代码的顺序将保持不变。

上面的代码是否可能发生锁定? 或者如果有多个进程正在写入 2 个文件, 可以锁吗?

我找到了相关的好文章,但我不相信它真的会发生。 Is a sync/flush needed before writes to a locked file from multiple threads/processes in fopen a+ mode? fputs and fflush, writing and buffer process

谢谢!

【问题讨论】:

  • 您是否在问为什么尽管没有锁定但您的输出仍按预期显示?还是您在问是否需要锁定?或者您是在问如何从多个并发进程正确写入同一个文件?还是别的什么?
  • 另外,请添加您的环境(特别是操作系统和文件系统),因为这将有助于提供具体的答案。
  • 我的问题是上面的代码会发生几次。当然,我知道有必要使用同步对象以及如何改进它。但是有问题的代码还没有它们。我只想知道是什么让程序挂起。环境是 HP unix,可能是 2 年内的最新版本。谢谢!
  • 您表示HP unix,购买代码执行'start filewrite.exe',并调用GetCurrentProcessId。听起来像 Windows。
  • @dash-o,嗨。是的。环境是HP unix。以上代码是我自己在家做的一个例子。

标签: c file concurrency locking fopen


【解决方案1】:

程序中有一个“隐藏”锁 - 当代码打开日志文件时,它使用 APPEND 模式(“a”打开)。这将导致在 open 系统调用上设置标志 O_APPEND。

引用 man open:

O_APPEND 该文件以附加模式打开。在每次 write(2) 之前,文件偏移量位于 文件的结尾,就像使用 lseek(2) 一样。文件偏移量的修改和 写操作作为单个原子步骤执行。

该标志保证每个“写入”操作(每当执行 printf 以将行刷新到文件时执行)将是原子的,并且不会与其他进程的输出混合。 同步和锁定发生在操作系统内核中,无需用户操作

【讨论】:

  • puts() 不能保证使用单个 write() 调用来实际将数据写入文件。也不是任何其他基于FILE * 的函数。
  • open( ..., O_WRONLY | O_APPEND ... ); 使用write( fd, buf, strlen( buf ) ); 写入文件描述符 假设你没有得到部分write()(技术上允许发生,但我已经从未在常规文件上见过),这几乎肯定是原子的 - 几乎必须是系统不兼容 POSIX,但极端情况可能会暴露问题。
  • @AndrewHenle 同意您的评论。但请参阅有关实际实施的评论后的评论。现实情况是,大多数现代系统默认会执行 512(最小,即使是嵌入式)到 4K 的缓冲区。到这边的任何消息。以新行终止,将通过单次写入发送
  • 输出是文件缓冲,而不是 tty,所以几乎可以保证随机交错。每个 fput 大约在 40 到 10280 个字符之间(由 rand() 控制)。
猜你喜欢
  • 2019-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-07
  • 2012-09-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多