如何强制正在运行的程序使用外部方法将其I / O缓冲区的内容刷新到磁盘?

我有一个长期运行的C程序,它在开始时打开一个文件,在执行期间写出“有趣”的东西,并在它完成之前关闭文件.使用gcc -o test test.c(gcc版本5.3.1.)编译的代码如下所示:

//contents of test.c
#include<stdio.h>

FILE * filept;

int main() {
    filept = fopen("test.txt","w");
    unsigned long i;
    for (i = 0; i < 1152921504606846976; ++i) {
        if (i == 0) {//This case is interesting!
            fprintf(filept, "Hello world\n");
        }
    }
    fclose(filept);
    return 0;
}

问题是,由于这是一个科学计算(想想搜索质数,或者你最喜欢的难以破解的东西),它可能真的运行了很长时间.由于我确定我没有足够的耐心,我想中止当前的计算,但我想通过某种方式以一种智能的方式通过外部手段强制程序清除当前在OS中的所有数据缓冲区/磁盘缓存,无论在哪里.

这是我尝试过的(对于上面的虚假程序,当然不适用于目前仍在运行的真实交易):

>按ctrl C;要么
>发送kill -6< PID> (并且还杀死-3< PID>) – 正如@BartekBanachewicz所建议的,

但是在这些方法中的任何一个之后,在程序的最开始创建的文件test.txt仍为空.这意味着,fprintf()的内容在计算过程中被留在某个中间缓冲区中,等待一些OS /硬件/软件刷新信号,但由于没有获得这样的信号,内容消失了.这也意味着@EJP的评论

Your question is based on a fallacy. ‘Stuff that is in the OS
buffer/disk cache’ won’t be lost.

似乎不适用于此.经验表明,这些东西确实迷失了.

我正在使用Ubuntu 16.04,如果可能的话,我愿意将调试器附加到此过程,并且如果以这种方式检索数据是安全的.由于我之前从未做过这样的事情,如果有人能给我详细解答如何安全可靠地将内容刷入磁盘,我将不胜感激.或者我也对其他方法持开放态度.这里没有错误的余地,因为我不打算再次重新运行该程序.

注意:当然我可以在if分支中打开和关闭一个文件,但是一旦你要编写很多东西,那就非常低效了.重新编译程序是不可能的,因为它仍处于某些计算的中间.

注2:原始问题以与C相关的稍微抽象的方式被问到相同的问题,并被标记为这样(这就是为什么评论中的人建议使用std :: flush(),即使这是一个C问题).好吧,我想我做了一个重大编辑.

有点相关:Will data written via write() be flushed to disk if a process is killed?

解决方法:

我可以添加一些清晰度吗?显然几个月过去了,我想你的程序不再运行了……但是这里有一些关于缓冲的混乱,但仍然不清楚.

一旦你使用stdio库和FILE *,默认情况下你的程序中会有一个相当小的(依赖于实现,但通常是一些KB)缓冲区,它会累积你写的内容,并在它满了时将它刷新到操作系统, (或关闭文件).当您终止进程时,就会丢失此缓冲区.

如果数据已刷新到操作系统,则将其保存在unix文件缓冲区中,直到操作系统决定将其持久保存到磁盘(通常很快),或者有人运行同步命令.如果你扼杀了计算机上的电源,那么这个缓冲区也会丢失.你可能不关心这种情况,因为你可能不打算扯下力量!但这就是@EJP所讨论的内容(重新设置在OS缓冲区/磁盘缓存中的东西’不会丢失):你的问题是stdio缓存,而不是操作系统.

在一个理想的世界中,你会编写你的应用程序,以便在关键点处进行刷新(或std :: flush()).在你的例子中,你会说:

    if (i == 0) {//This case is interesting!
        fprintf(filept, "Hello world\n");
        fflush(filept);
    }

这将导致stdio缓冲区刷新到操作系统.我想你的真正的作家更复杂,在那种情况下,我会尝试使fflush“经常但不经常”发生.太罕见了,当你终止这个过程时会丢失数据,而且如果你写的很多,你会失去缓冲的性能优势.

在您描述的情况下,程序已经运行且无法停止和重写,那么您唯一的希望就是在调试器中停止它.你需要做什么的细节取决于std lib的实现,但你通常可以查看FILE * filept对象并开始关注指针,但是它很乱. @ ivan_pozdeev关于在调试器中执行std :: flush()或fflush()的注释很有帮助.

上一篇:MySQL drop table 影响及过程


下一篇:虚拟机搭建kafka集群(Center OS 7)