【问题标题】:c code: fprintf from multiples codes to the same filec代码:fprintf从多个代码到同一个文件
【发布时间】:2021-02-23 09:44:30
【问题描述】:


我对fprintf() 的工作原理有些怀疑。我读到fprintf() 不能保证对它正在写入的文件执行原子附加操作。 这在实践中意味着什么?
考虑以下简单情况,例如:
在同一个文件夹中,我有相同代码的不同副本(下面的代码)同时运行并将值打印到一个公共文件(Data.txt)中,例如:\

#define N 10000000
int main(){
    FILE* fp_Data;
    fp_Data=fopen("Data.txt", "a");

    srand48(time(NULL));

    int i;
    double u;
    for(i=0; i<N; i++){
        u = drand48();
        fprintf(fp_Data, "%f\n", u);
    }
    fclose(fp_Data);

}

会不会出现问题(覆盖数据/丢失数据)?
[编辑]
正如 Damien 所指出的,关于这个问题有一个类似的问题(Is fprintf() thread safe?)
在那个问题中,它讨论的是同一进程的不同线程,而不是指向同一个 FILE* 的独立进程。
在这种情况下,对于 POSIX 标准(这是我应该在任何带有 unix SO 的 PC 上考虑的标准?)保证线程安全,这意味着我不会冒被覆盖/丢失数据问题的风险。我现在的疑问是:
指向同一个 FILE* 的独立进程也是如此吗?

【问题讨论】:

  • 这能回答你的问题吗? Is fprintf() thread safe?
  • 从我读到的他说的是同一进程的不同线程,而不是指向同一个文件*的独立进程。无论如何,只是为了确保理解答案,在他的情况下(fprintf() 来自同一进程的不同线程的调用),POSIX 标准(这是我应该在带有 unix SO 的 PC 上考虑的标准?)保证线程 -安全性,这意味着我不会冒被覆盖/丢失数据问题的风险。对吗?
  • 这也是我的理解。请注意,我不是该领域的专家。但是,我提到的帖子似乎相当肯定和明确。
  • "同时运行不同的代码并将值打印到一个公共文件中," --> 发布用于打开文件的代码——尤其是模式
  • chux - 恢复莫妮卡,我添加了一个具体而简单的案例来更好地解释我的疑问

标签: c append printf buffer atomic


【解决方案1】:

只要文件以追加模式打开,对文件的每个底层写入都会自动追加到相关文件。

只要 FILE 处于行缓冲模式并且没有行长于 FILE 对象的底层缓冲区大小,每一行都将通过对底层文件的一次写入调用来写入。

您使用 fopen 的"a" 模式以追加模式打开文件。可以在打开文件后立即使用setvbuf设置文件的缓冲区大小和缓冲模式。

setvbuf(fp_Data, NULL, _IOLBF, 1024);

如果您将 FILE 保留在默认的块缓冲模式下,它将在缓冲区填满时写入底层文件,这可能位于一行的中间。如果多个进程以追加模式写入,这将导致文件中的行混乱。


另一种方法是每次“记录”完成时显式地刷新文件(可能是多行)。只要您的记录总是小于缓冲区大小,这将导致每条记录自动附加到文件中。

【讨论】:

  • 谢谢克里斯·多德,非常明确的答案。我对缓冲区管理只有一个疑问:如果我减少缓冲区(相对于默认块模式),强制它进入行模式或无缓冲模式,如果磁盘忙,我是否有可能错过一些写入片刻(代码传递到nexts迭代并且磁盘无法回调之前的数据)?我最好在以下两个问题中暴露我的疑问:stackoverflow.com/questions/66332796/…stackoverflow.com/questions/66305027/…
  • 第一个链接是关于一般缓冲机制和在没有缓冲模式的情况下丢失数据的可能性。相反,第二个是我从fprintf() 调用中丢失了一些数据的真实情况(我不确定那里发生了什么)
  • 在 POSIX 上,除非出现磁盘错误,否则不会丢失任何数据——如果没有可用的缓冲区,则 write 调用将阻塞等待磁盘。如果存在磁盘错误,则应将其报告为失败,无论是在写入时(fprintf 将失败,在 FILE 上设置错误标志)还是在关闭时(fclose 将失败)。
  • 要查看何时发生此类磁盘错误,我必须明确检查 fprintf() 的返回值并检查它是否为负,对吗?例如,在命令 StampStatus = fprintf(fp_Data, "%f\n", u); 之后有一个 if 条件,如下所示:if(StampStatus &lt;0){ printf("fprintf writing error\n"); } "fprintf will fail, setting the error flag on the FILE" 如果我​​看到错误标志在文件中也没有前面的 if(或类似)检查?
  • 之后检查 fprintf 的返回值或检查 ferror(fp) 就足够了 - 错误将设置标志,并且在您明确清除它之前将保持设置。但是,即使是“成功”,通常也只是意味着数据已成功写入内核的缓冲区缓存——稍后将缓存刷新到磁盘时可能会出现问题。否则磁盘上的数据可能会在写入后损坏。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多