在C ++ 11中,在给定一种请求循环(作为Web请求循环的一部分)的情况下,对被捕获的信号执行不安全代码的最安全(并且是最有效的)方法是什么?例如,从linux命令行捕获SIGUSR1:kill -30 <process pid>
可以接受在下一个被触发的请求上运行“不安全代码”,如果在运行不安全代码之前多次触发信号,则不会丢失任何信息。
例如,我目前的代码是:
static bool globalFlag = false;
void signalHandler(int sig_num, siginfo_t * info, void * context) {
globalFlag = true;
}
void doUnsafeThings() {
// thigns like std::vector push_back, new char[1024], set global vars, etc.
}
void doRegularThings() {
// read filesystem, read global variables, etc.
}
void main(void) {
// set up signal handler (for SIGUSR1) ...
struct sigaction sigact;
sigact.sa_sigaction = onSyncSignal;
sigact.sa_flags = SA_RESTART | SA_SIGINFO;
sigaction(SIGUSR1, &sigact, (struct sigaction *)NULL);
// main loop ...
while(acceptMoreRequests()) { // blocks until new request received
if (globalFlag) {
globalFlag = false;
doUnsafeThings();
}
doRegularThings();
}
}
我知道在主循环测试中可能存在问题+设置globalFlag boolean。
编辑:if (globalFlag)
测试将在相当紧密的循环中运行,并且可以接受“偶尔”的假阴性。但是,我怀疑Basile Starynkevitch的解决方案还没有优化呢?
答案 0 :(得分:6)
你应该声明你的旗帜
static volatile sig_atomic_t globalFlag = 0;
参见例如sig_atomic_t,this question并且不要忘记volatile
限定符。 (C可能拼写为sigatomic_t
。
在Linux(特别是)上,您可以使用signalfd(2)获取信号的文件描述符,并且fd可以是poll(2) - 由您的事件循环编辑。
某些事件循环库(libevent,libev ...)知道如何处理信号。
还有在初始化时设置管道(请参阅pipe(2)以获取更多信息)的技巧,并在信号处理程序中仅write(2)处理一些字节。事件循环将轮询并读取该管道。
另请阅读signal(7)(它解释了信号处理程序中可用的有限函数或系统调用的内容)....
顺便说一句,正确性比效率更重要。一般情况下,您获得的信号很少(例如,大多数程序最多每秒钟获得一次信号,而不是每毫秒一次)。