【问题标题】:Is it possible to freeze and dump state of program?是否可以冻结和转储程序状态?
【发布时间】:2017-03-09 03:51:33
【问题描述】:

考虑这样的情况: 有一个简单的程序:

int main()

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

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

【问题讨论】:

  • 最简单的方法是重写你的程序,让它接收一个特定的信号,并将它自己的状态保存在某个地方。然后将检查后续运行的状态。
  • 你想“继续”做什么?你说的冻结是什么意思?你的程序是做什么的?
  • 你需要的技术叫做serialization
  • 如果“冻结”程序的事件在内部是已知的——即使在编译时——会有一个答案,如果有一个未知的时刻程序将被“冻结”,则会有另一个答案.
  • 您可以生成故障转储,但这是特定于编译器的,可能不包含整个程序状态,尤其是在发布版本时。

标签: c++ linux serialization


【解决方案1】:

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

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;
}

【讨论】:

    【解决方案2】:

    Linux 内核绝对可以做到这一点,因为程序状态可以在必要时存储在交换区域中,然后再恢复。唯一的问题是 API 是否提供了此类功能。据我所知,它不可用,我严重怀疑它永远不会存在。这个任务实现起来太复杂了——你需要存储所有打开的文件、套接字、IPC资源等。当你试图恢复状态时,不清楚该怎么做,但是你的程序打开的文件丢失了。使用 TCP 套接字时情况更糟。

    【讨论】:

      【解决方案3】:

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

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

      2) 启动您的简单程序,并获取它的 PID。

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

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

      1) gdb myprogram core.PID

      你会看到类似的东西:

      “程序以信号 SIGABRT 终止,已中止。”

      2) 使用 gdb 命令运行启动程序。

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

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

      【讨论】:

        【解决方案4】:

        你想做的事叫做application checkpointing。另请阅读persistencecall stackdynamic software updatingcontinuation(&CPS)、databaseASLRGarbage Collection(因为复制 GC 使用的算法非常接近检查点所需的算法) , serialization, process migration wikipages,因为它们都是相关的。

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

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

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

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

        • 如果您的进程有 Graphical User Interface(它正在与 X11 或 Wayland 服务器通信)。

        • 1234563更改了编译(例如优化)标志。
        • 对于多线程应用程序,您会遇到很多额外的问题(例如,如何从检查点状态重新启动它们等...)

        某些情况下,您可能会为此使用一些检查点库。查看BLCR

        在其他情况下,它超越了最先进的技术,仍然是一个活跃的研究课题。你可以在这方面工作大约十年并获得博士学位。

        在实践中,检查点非常重要,您应该在开始编写第一行 C++ 代码之前考虑一下。它对您的软件架构设计有着深远的影响。

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

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

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

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

        PS。很不幸,您的问题没有提供更多的背景和动机。确定不是XY problem

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-03-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多