是否可以冻结和转储程序状态?



考虑如下情况:有一个简单的程序:

int main()
{
    for (int i = 0; i < 100; i++) {
        if (i == 50){
            // ... dump state of program somewhere
        }
        cout << i << " ";
    }
    return 0;
}

是否有可能"保存"程序的状态可能通过存储这个状态到磁盘上的文件?例如,几周后,我想从文件中加载这个状态,它将继续从最后一站位置工作(它将打印50 51 ...)。

你要做的叫做应用程序检查点。读也持久化,调用栈,软件动态更新,延续(&CPS),数据库,ASLR,垃圾收集(因为复制GC使用的算法非常接近检查点所需的算法),序列化,处理迁移页面,因为它们都是相关的。

当然,在有限的情况下,您可以转储核心转储并重新启动它(正如大多数其他答案所建议的那样)。但这可能行不通:

  • 如果你的(检查点)进程与其他服务器有网络连接(例如使用libcurl访问远程网页或内容)

  • 如果您的进程启动了其他进程,并且正在通过管道或fifo与它们通信

  • 如果您的进程依赖于外部服务,如数据库服务器。

  • 如果你的进程有一个图形用户界面(它正在与X11或Wayland服务器通信)

  • 如果你想在几周后重新启动你的进程,并且你已经稍微改进和重新编译了它的代码(甚至在一些与计算无关的地方),或者可能只是升级了外部库,c++编译器,或者改变了编译(例如优化)标志。

  • 对于多线程应用程序,你会有很多额外的问题(例如如何从检查点状态重新启动它们,等等…)

某些情况下,您可以使用一些检查点库。查看BLCR

在其他情况下,它是高于目前的技术水平,仍然是一个活跃的研究课题。你可以在上面工作十年,然后拿到博士学位。

在实践中,检查点是如此重要,以至于您应该在开始编写第一行c++代码之前考虑它。它对软件架构的设计有深远的影响。

在某些情况下,甚至值得花几个星期的时间来开发专门的c++代码生成器(以生成持久性代码)。检查点)。

在某些领域,特别是HPC &在超级计算机上进行许多科学计算时,检查点是必不可少的;例如,模拟两个星系的碰撞可能需要在一台非常昂贵的超级计算机上进行数月的计算(在如此庞大的模拟结束之前可能会重新启动),当然,在编写第一行代码之前,您需要考虑检查点。如果代码本质上是非常迭代的,它实际上可能很简单(原则上),因为您"只"需要将计算的数据保存在某个高级循环中。在实践中,它是复杂的,邪恶在细节中。

一些语言实现对检查点的支持有限。例如(在Common Lisp中)SBCL提供了它的save-lisp-and-die原语。GNU emacs有unexec(但也要注意这里,因为它可能会过时)。

应用程序持久化和数据是一个非常重要的主题。在许多情况下,数据比应用程序本身更有价值(那么,你应该对数据库感兴趣,从Sqlite到PostGreSQL & &;MongoDB)。

p。很不幸,你的问题没有提供更多的背景信息。动机。你确定这不是XY的问题吗?

这类事情通常需要手工完成。用你的例子:

int main()
{
    ifstream input("program_status.txt");
    int start = 0;
    if (input.good())
        input >> start; // TODO Validate!!!
    for (int i = start; i < 100; i++) {
        cout << i << " ";
        if (i == 50){
            ofstream output("program_status.txt");
            // continue next time
            output << (i+1);
            return 0;
        }
    }
    return 0;
}

Linux内核绝对可以做到这一点,因为程序状态可以在必要时存储在交换区,然后恢复。唯一的问题是这种功能是否由API提供。据我所知,这是不可能的,而且我非常怀疑这将是永远。这个任务太复杂了,无法实现——你需要存储所有打开的文件、套接字、IPC资源等。当您尝试恢复状态时,不清楚该怎么做,但是程序打开的文件丢失了。对于TCP套接字,情况更糟。

我向您展示的技术只适用于简单的程序。正如Slava所说,之前打开的所有设备和资源都将无法访问。它只适用于简单的程序,没有文件或套接字打开。

1)使用ulimit -a验证创建核心文件的能力。如果核心大小为0,则不会创建任何核心,因此将值增加到足以包含您的程序的大小。您可以使用ulimit -c

设置

2)启动你的简单程序,并得到它的PID。

3)发送kill -SIGABRT,您的程序将被停止,并将创建一个核心转储文件,以PID为后缀。

核心转储文件是您已停止运行的程序。要重新启动它,使用gdb

1) GDB myprogram核心。PID

你会看到这样的内容:

"程序以信号SIGABRT终止,已终止。"

2)用GDB命令运行程序

最后一点,如果你想用gdb再次生成一个新的停止点,你可以再次向你的程序发送SIGABRT,但是你需要手动生成核心文件,当你的程序使用gdb运行时,它不会自动生成。

生成核心文件的gdb命令为:generate-core-file

最新更新