setitimer 信号似乎只在分叉后工作

Posted

技术标签:

【中文标题】setitimer 信号似乎只在分叉后工作【英文标题】:setitimer signalling seems only to work after fork 【发布时间】:2014-05-19 01:53:33 【问题描述】:

我想使用以下 C++ 代码等待预定义的时间量(在此示例中始终为 2 秒),但仍可被信号中断(这就是我不使用睡眠的原因):

#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/time.h>
#include <signal.h>
#include <iostream>

using namespace std;

int measure() 
  itimerval       idle;
  sigset_t        sigset;
  int             sig;

  idle.it_value.tv_sec  = 2;
  idle.it_value.tv_usec = 0;
  setitimer(ITIMER_REAL, &idle, NULL);  // TODO: check return value

  sigemptyset(&sigset);
  sigaddset(&sigset, SIGALRM);  // TODO return values
  sigaddset(&sigset, SIGUSR1);

  sigprocmask(SIG_BLOCK, &sigset, NULL);  // TODO return value?
  sigwait(&sigset, &sig);  // TODO check return value
  while(sig != SIGUSR1) 
    cout << "Hohoho" << endl;

    idle.it_value.tv_sec  = 2;
    idle.it_value.tv_usec = 0;
    setitimer(ITIMER_REAL, &idle, NULL);  // TODO: check return value
    sigwait(&sigset, &sig);  // TODO check return value
   

  cout << "Done with measurements." << endl;
  return 0;


int main(int argc, char **argv) 
  //if(fork() != 0) exit(0);
  //if(fork() == 0) exit(0);
  return measure();

我希望这段代码每 2 秒打印一次“Hohoho”,直到它收到 SIGUSR1。然后它打印“完成测量”。并退出。第二部分按预期工作。但是,我没有看到“Hohoho”,所以在我看来,来自 setitimer 的 SIGALRM 以某种方式没有收到。奇怪的是,如果我之前做一个 fork,程序会按预期工作。更具体地说,如果我在最后取消注释两个 fork 命令中的任何一个,它就可以工作。因此,它不取决于它是父进程还是子进程,但不知何故,fork 事件很重要。有人可以向我解释发生了什么以及如何修复我的代码吗?

非常感谢, 卢茨

【问题讨论】:

【参考方案1】:

(1) 您的setitimer 失败,因为您没有正确设置它。结构 itimerval 包含两个 timeval 类型的结构。当idle 被声明时,您只设置了一个,从而拾取本地存储中的任何垃圾。

       struct itimerval 
           struct timeval it_interval; /* next value */
           struct timeval it_value;    /* current value */
       ;

       struct timeval 
           time_t      tv_sec;         /* seconds */
           suseconds_t tv_usec;        /* microseconds */
       ;

如果您想要每 2 秒重复一次计时器,请将第二组设置为使用相同的值重复。

  idle.it_value.tv_sec  = 2;
  idle.it_value.tv_usec = 0;
  idle.it_interval.tv_sec  = 2;
  idle.it_interval.tv_usec = 0;

【讨论】:

谢谢,鸭子。在我的真实代码中,我不想一遍又一遍地设置相同的时间,而是确定警报后的下一个间隔。所以我应该将 it_interval 设置为 0,然后像上面的代码一样明确地重置计时器。我首先犯了一个错误,但最终它修复了它。再次感谢。

以上是关于setitimer 信号似乎只在分叉后工作的主要内容,如果未能解决你的问题,请参考以下文章

信号的发送kill,raise,alarm,setitimer,abort,sigqueue

Qt 应用程序在分叉到后台时意外收到 HUP 信号

Linux定时器

linux 进程通信之 信号

分叉的子进程是不是使用相同的信号量?

信号