static void AlarmHandler(int sig) ;
int i=0;
jmp_buf mark;
int main(int argc, char * argv[]){
setjmp(mark);
signal(SIGALRM, AlarmHandler);
alarm(2);
while(1);
return 0;
}
static void AlarmHandler(int sig) {
signal(SIGALRM, SIG_IGN);
printf("I am in AlarmHandler: %d \n",i);
i++;
longjmp(mark, 0);
}
当我运行此代码时,程序只通过AlarmHandler一次,然后它就会被困在while循环中。有人可以解释原因吗?
答案 0 :(得分:2)
您的程序可能正如您在某些POSIXy操作系统上所期望的那样 - 事实上, 按照您在计算机上的预期工作<我>打字。然而,它依赖于一系列与信号有关的未明确的行为,我认为你已经绊倒了其中一个:我认为在你的计算机上,一个信号已被阻止&#34; - 它不能再次传递 - 当它的处理程序正在执行时,并且,使用longjmp
跳出处理程序会使不解锁信号。所以你绕过循环一次,然后第二个SIGALRM永远不会被传递,因为它被阻止了。还有其他一些相关问题。
您可以确定所有未指定的行为并使程序在所有POSIXy操作系统上都可靠,但您必须使用不同的功能进行设置:sigsetjmp
和sigaction
。你也应该使用sigsuspend
来摆脱忙碌的等待。修正后的程序看起来像这样:
#define _XOPEN_SOURCE 700
#include <signal.h>
#include <setjmp.h>
#include <stdio.h>
#include <unistd.h>
static jmp_buf mark;
static void
handle_SIGALRM(int sig)
{
static int signal_count;
signal_count++;
printf("SIGALRM #%u\n", signal_count);
siglongjmp(mark, signal_count);
}
int
main(void)
{
sigset_t mask, omask;
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
if (sigprocmask(SIG_BLOCK, &mask, &omask)) {
perror("sigprocmask");
return 1;
}
struct sigaction sa;
sigfillset(&sa.sa_mask);
sa.sa_flags = 0; // DO interrupt blocking system calls
sa.sa_handler = handle_SIGALRM;
if (sigaction(SIGALRM, &sa, 0)) {
perror("sigaction");
return 1;
}
if (sigsetjmp(mark, 1) >= 4)
return 0;
alarm(1);
sigsuspend(&omask);
perror("shouldn't ever get here");
return 1;
}
我应该对信号安全说几句话:在这个程序中, 可以安全地从printf
和siglongjmp
调用信号处理程序,因为我已安排SIGALRM 仅可交付,而主要执行线程在sigsuspend
被阻止。 (那就是对sigprocmask
的调用是什么。)如果你在主执行线程中有任何事情除了睡觉等待信号到达,你会必须much more careful关于你在信号处理程序中所做的事情,我会主张使用pselect
和/或self-pipe trick而不是跳出处理程序,如果可能的话。