【问题标题】:can't get alarm() to work more than twice不能让 alarm() 工作超过两次
【发布时间】:2023-03-18 03:33:01
【问题描述】:
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 循环中。谁能解释一下原因?

【问题讨论】:

  • 您的i 应该是volatile sig_atomic_t。另外,您为什么要使用 setjmp/longjmp ?这可以以更简洁的方式实现......而且你不应该在信号处理程序中使用库函数。
  • @EugeneSh。这不是我正在开发的程序。这只是我遇到麻烦的部分。 setjmp/longjmp 在这里确实是不必要的,但我确实需要它。

标签: c alarm setjmp


【解决方案1】:

您的程序可能在某些 POSIXy 操作系统上按您预期的方式运行——事实上,它确实在我正在输入此内容的计算机上按您预期的方式运行。然而,它依赖于一堆与信号相关的未指定行为,我认为你已经绊倒了其中一个:我认为在你的计算机上,一个信号被“阻塞”——它不能再次传递——而它的处理程序正在执行,而且,使用longjmp 跳出处理程序不会解除对信号的阻塞。所以你绕过循环一次,然后第二个 SIGALRM 永远不会传递,因为它被阻塞了。还有其他几个相关的问题。

您可以确定所有未指定的行为并使程序在所有 POSIXy 操作系统上都可靠,但您必须使用不同的函数进行设置:sigsetjmpsigaction。您还应该改用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;
}

关于信号安全,我大概应该说几句:在 this 程序中,从信号处理程序调用 printfsiglongjmp 是安全的,因为我已安排 SIGALRM only 可交付,而主执行线程在 sigsuspend 上被阻塞。 (这就是调用 sigprocmask up top 所做的事情。)如果您在主执行线程中有任何事情要做除了 sleep 等待信号到达,您必须是 much more careful关于你在信号处理程序中所做的事情,如果可能的话,我会提倡使用pselect 和/或self-pipe trick 而不是跳出处理程序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-05
    • 1970-01-01
    • 2017-06-20
    • 2011-07-28
    • 1970-01-01
    • 1970-01-01
    • 2021-07-18
    • 1970-01-01
    相关资源
    最近更新 更多