中断运行程序并保存数据

时间:2011-08-12 11:28:31

标签: c++ c linux

如何设计C / C ++程序,以便在接收到中断信号后可以保存一些数据。

我有一个长时间运行的程序,我可能需要在它完成运行之前杀死(例如,通过按Ctrl-C)。当被杀死(而不是跑到结束)时,程序应该能够将一些变量保存到磁盘。我有几本很大的Linux书籍,但不太清楚从哪里开始。食谱配方会非常有用。

谢谢。!

5 个答案:

答案 0 :(得分:4)

你想做的事情并非无足轻重。您可以首先使用signalsigaction为SIGINT(C-c)安装信号处理程序,然后启动硬件

主要问题是在信号处理程序中,您只能调用async-signal-safe functions(或reentrant个函数)。大多数库函数不能被可靠地认为是可重入的。例如,stdio个函数,mallocfree以及许多其他函数都不可重入。

那你怎么处理这个?在处理程序中设置flag(将一些全局变量done设置为1)并查找EINTR错误。在处理程序之外进行清理应该是安全的。

答案 1 :(得分:4)

要做到这一点,你需要让你的程序看一些东西,例如一个全局变量,告诉他停止它正在做的事情。

例如,假设您的长时间运行的程序执行循环,您可以这样做:

g_shouldAbort = 0;
while(!finished)
{
   // (do some computing)

   if (g_shouldAbort)
   {
      // save variables and stuff
      break; // exit the loop
   }
}

将g_shouldAbort定义为全局 volatile 变量,如下所示:

static volatile int g_shouldAbort = 0;

(将它声明为“volatile”非常重要,否则编译器会看到没有人在循环中写入它,可能会认为if(g_shouldAbort)将始终为false并将其优化掉。)

然后,使用其他用户建议的信号 API,您可以这样做:

void signal_handler(int sig_code)
{
   if (sig_code == SIGUSR1) // user-defined signal 1
      g_shouldAbort = 1;
}

(当然,您需要注册此处理程序,参见here

signal(SIGUSR, signal_handler);

然后,当您向程序“发送”SIGUSR1信号时(例如使用 kill 命令),g_shouldAbort将设置为1,程序将停止计算。

希望这有帮助!

注意:这种技术很简单但很粗糙。使用信号和全局变量使得当然很难使用多个线程,正如其他用户所概述的那样。

答案 2 :(得分:3)

您要做的事情属于检查点/重启的标题。

使用信号驱动方案进行检查点/重启时存在几个大问题。一个是信号处理程序必须非常紧凑且非常原始。您无法在信号处理程序中编写检查点。另一个问题是,当发送信号时,您的程序可以在任何地方处于执行状态。这个随机位置几乎肯定不是一个可以放弃检查点的安全点。另一个问题是你需要为你的程序配备一些应用程序端检查点/重启功能。

我建议您考虑使用已经存在的免费检查点/重启功能,而不是滚动自己的检查点/重启功能。 linux上的gdb提供了检查点/重启功能。另一个是DMTCP,请参阅http://dmtcp.sourceforge.net/index.html

答案 3 :(得分:0)

使用signal(2)sigaction(2)分配一个指向SIGINT信号的函数指针,并在那里进行清理。

答案 4 :(得分:0)

让您只在保存功能中输入一次

// somewhere in main
signal( SIGTERM, signalHandler );
signal( SIGINT,  signalHandler );

void saveMyData()
{
    // save some data here
}

void signalHandler( int signalNumber )
{
    static pthread_once_t semaphore = PTHREAD_ONCE_INIT;
    std::cout << "signal " << signalNumber << " received." << std::endl;
    pthread_once( & semaphore, saveMyData );
}

如果您的过程在完成文件编写之前得到2个或更多信号,您将保存奇怪的数据