考虑这种情况: 有一个简单的程序:
int main()
{
for (int i = 0; i < 100; i++) {
if (i == 50){
// ... dump state of program somewhere
}
cout << i << " ";
}
return 0;
}
是否可以通过将此状态存储到磁盘上的文件来“保存”程序状态?例如,几周后我想从文件中加载此状态,它将从上一个停止位置继续工作(它将打印50 51 ...
)。
答案 0 :(得分:2)
您要做的是application checkpointing。另请阅读persistence,call stack,dynamic software updating,continuation(&amp; CPS),database,ASLR,{{ 3}}(因为复制GC使用的算法非常接近于检查点所需的算法),Garbage Collection,serialization wikipages因为它们都是相关的。
当然,在有限的情况下,您可以转储process migration并重新启动它(正如大多数其他答案所建议的那样)。但这可能行不通:
如果您的(检查点)流程与其他服务器有网络连接(例如,使用core dump访问远程网页或内容)。
如果您的流程已启动其他流程并通过管道或fifos与它们进行通信
如果您的流程依赖于外部服务,例如数据库服务器。
如果您的流程有libcurl(它正在与X11或Wayland服务器通信)。
如果你想在几周后重新启动你的进程,你稍微改进并重新编译它的代码(即使在某些与计算无关的地方),或者只是升级外部库,C ++编译器,或者改变了编译(例如优化)标志。
对于多线程应用程序,您会遇到很多其他问题(例如,如何从检查点状态重新启动它们等等)
在某些情况下,您可以使用一些检查点库。查看Graphical User Interface
在其他情况下,它高于现有技术,仍然是一个活跃的研究课题。你可以工作大约十年,并获得博士学位。
在实践中,检查点非常重要,您应该在开始编写第一个C ++行之前考虑它。它对软件架构的设计产生了深远的影响。
在某些情况下,甚至值得花几周时间开发专门的C ++代码生成器(生成持久性和检查点的代码)。
在某些领域,特别是HPC&amp;关于BLCR的许多科学计算,检查点是必不可少的;例如,模拟两个星系的碰撞可能需要在非常昂贵的超级计算机上进行数月的计算(可能会在如此巨大的模拟结束之前重新启动),然后当然在编写第一行代码之前需要考虑检查点。它实际上可能很简单(原则上),如果代码本质上是迭代的,因为你“只是”需要保存在某个高级循环中计算的数据。在实践中,它是复杂的,邪恶在于细节。
某些语言实现对检查点的支持有限。例如(在Common Lisp中)supercomputers提供其SBCL原语。 GNU emacs有save-lisp-and-die
(但也看unexec,因为它可能已经过时了。)
应用程序持久性和数据是一个非常重要的主题。在许多情况下,数据比应用程序本身更有价值(那么,您应该对数据库感兴趣,从here到Sqlite&amp; PostGreSQL)。
PS。非常不幸的是,你的问题并没有提供更多的背景信息。动机。你确定它不是MongoDB吗?
答案 1 :(得分: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 :(得分:1)
Linux核心肯定可以做到这一点,因为程序状态可以在必要时存储在交换区域中,然后恢复。唯一的问题是API是否提供了此类功能。正如我所知,它不可用,我严重怀疑它会永远存在。此任务太复杂而无法实现 - 您需要存储所有打开的文件,套接字,IPC资源等。当您尝试恢复状态时,不清楚该怎么做,但是程序打开的文件丢失了。使用TCP套接字更糟糕。
答案 3 :(得分:1)
我向您展示的技术仅适用于简单的程序。 正如Slava所说,以前打开的所有设备和资源都无法访问。它只适用于简单的程序,没有打开文件或套接字。
1)用ulimit验证 - 是否能够创建核心文件。如果核心大小为0时为value,则不会创建核心,因此将值增加到足以包含程序的大小。您可以使用ulimit -c
进行设置2)启动你的简单程序,并获得它的PID。
3)发送kill -SIGABRT,你的程序将被停止,并且将创建一个以后缀为PID的核心转储文件。
核心转储文件是您停止运行的程序。要重新启动它,请使用gdb
1)gdb myprogram core.PID
你会看到一些像:
“程序终止,信号SIGABRT,已中止。”
2)用gdb命令运行启动程序。
最后一点,如果你想再次使用gdb生成一个新的停止点,你可以再次向你的程序发送SIGABRT,但你需要手动生成核心文件,当你的程序与gdb一起运行时不会自动生成
生成核心文件的gdb命令是:generate-core-file