如何设计C / C ++程序,以便在接收到中断信号后可以保存一些数据。
我有一个长时间运行的程序,我可能需要在它完成运行之前杀死(例如,通过按Ctrl-C)。当被杀死(而不是跑到结束)时,程序应该能够将一些变量保存到磁盘。我有几本很大的Linux书籍,但不太清楚从哪里开始。食谱配方会非常有用。
谢谢。!
答案 0 :(得分:4)
你想做的事情并非无足轻重。您可以首先使用signal
或sigaction
为SIGINT(C-c)安装信号处理程序,然后启动硬件。
主要问题是在信号处理程序中,您只能调用async-signal-safe functions(或reentrant个函数)。大多数库函数不能被可靠地认为是可重入的。例如,stdio
个函数,malloc
,free
以及许多其他函数都不可重入。
那你怎么处理这个?在处理程序中设置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个或更多信号,您将保存奇怪的数据