当您在程序执行时向程序发送SIGUSR1
信号(假设信号处理程序已提前设置)时sleep(100)
,信号会被正确捕获,但sleep(100)
会在捕获后立即终止。这可能意味着发送信号可以强制终止内部某些功能。
例如,在科学计算程序中,我想捕获SIGUSR1
并打印进度。但是,如果我碰巧在has_error_occured = true
或 之类的语句should_break_this_roop = true
正在执行时发送信号怎么办?我认为这可能会导致意外的行为。
如何安全地使用SIGUSR1
(和SIGUSR2
)?众所周知,shell 命令dd
在捕获时会打印进度SIGUSR1
。为什么这样安全?
示例程序(我执行的kill -SIGUSR1 xxxxx
):
#include <iostream>
#include <csignal>
#include <unistd.h>
void my_handler(int signal) {
; //some instructions
}
void just_sleep() {
std::cout << "sleep() starts.\n";
sleep(100); //not wait for 100s if a signal caught
std::cout << "sleep() ends.\n"; //executed even if a signal caught
}
int main() {
signal(SIGUSR1, my_handler);
just_sleep();
}
答案1
您应该使用设置信号处理程序信号动作(2)代替信号(2),如果您不希望它中断阻塞系统调用,则进行SA_RESTART
设置。sa_flags
struct sigaction sa;
sa.sa_handler = your_handler;
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
sigaction(SIGUSR1, &sa, 0);
或者,甚至更好的是,您自己处理中断。
如果nanosleep()等返回-1,则检查是否errno == EINTR
,并打印进度,然后重做调用(sleep()只是linux上nanosleep()的包装器)。如果您的程序变得更复杂,您无论如何都必须这样做 - 您无法通过信号处理程序安全地做很多事情 - 请参阅signal-safety(7) 手册页在 Linux 上。