【问题标题】:Trouble with Interval Timer间隔定时器有问题
【发布时间】:2011-04-09 12:02:37
【问题描述】:

我们当前的项目基于通过包含滚动扩展 more。为此,必须为特定时间段设置定时器间隔。我不确定的部分是警报信号的循环应该在哪里。我见过的所有示例在 main 中都有计时器值,然后在无限循环中通过 pause() 显式调用信号处理程序。

我的代码有点不同,因为功能要求是这样的

print first screen of text after getting terminal dimensions
print prompt
   if prompt = space, print another screen of text //WORKS
   if prompe = q, restore original terminal settings & quit program //WORKS
   if prompt = ENTER, initialize scroll at 1 line every 2 seconds //DOESN'T WORK
   if prompt == f/s, increase/decrease scroll speed by 20%  //DOESN'T WORK

读入缓冲区、文件指针和itimerval struct都是全局变量,以避免作为参数通过函数链传递。

程序的主要功能是

void processInput(FILE *fp){
  void printLine(int); //prints a single line of text
  signal(SIGPROF, printLine);
  int c;

  //print first screen of text, check for more text to display

  info(); //print prompt at bottom of screen
  FILE *fterm= fopen("/dev/tty", "r");

  while ((c=getc(fterm)) != EOF){
    if (c== '\n'){
      setTimer(2);

     //four more conditionals like this in basic similarity

  }
}

我的 setTimer 函数的基本间隔为 2 秒,并根据用户的 f/s 输入将其更改为正/负 20%。

void setTimer(int direction){
  int speed=2000000; //2 seconds
  int change= 400000; //400 milliseconds, 20% of 2 seconds
  if (direction == 1) //slow down by 20%
    speed+= change;
  if (direction == 0)
    speed -= change;

  timer.it_value.tv_sec=2;
  timer.it_value.tv_usec=0;
  timer.it_interval.tv_sec=0;
  timer.it_interval.tv_usec= speed;

  setitimer(ITIMER_PROF, &timer, NULL);

}

第一个问题:我应该使用 SIGALRM 还是 SIGPROF,并相应地更改 ITIMER_XXXX 变量?

其次,我应该在哪里放置循环来触发信号?我试过了

while(1)
  pause();

在几个条件句中,但它具有停止执行并忽略任何输入的效果。

【问题讨论】:

    标签: c unix timer


    【解决方案1】:

    在不了解您的需求细节的情况下,您不能更轻松地使用 select()?

    将你的初始选择超时设置为2秒,并根据f/s输入进行调整,同时如果在超时之前有任何标准输入,你就处理它。

    大致有效的大纲:

       int retval;
    fd_set rfds;
    
    int input = fileno(fterm);
    
    struct timeval tv, delay;
    
    delay.tv_sec  = 2;
    delay.tv_usec = 0;
    
    while (true)
    {
        FD_ZERO(&rfds);
        FD_SET(input, &rfds);
    
        tv.tv_sec  = delay.tv_sec;
        tv.tv_usec = delay.tv_usec;
    
        retval = select(input + 1, &rfds, NULL, NULL, &tv);
    
        if (retval == -1)
            perror("select()");
        else
            if (retval)
            {
                if (FD_ISSET(input, &rfds))
                {
                    command = readInput(...);
    
                    switch(command)
                    {
                        case 'q' ... cleanup & quit
                        case 's' ... calc 20% off delay values
                        case etc ...
                        case default...error handling
                    }
                }
            }
            else //timeout
                printLine();
    }
    

    【讨论】:

      【解决方案2】:

      使用pause() 是危险的,因为它不是原子操作……您的程序可能会被操作系统中断,导致您“丢失”信号的到来。此外,当pause() 自身因信号到达而返回时,它会简单地再次调用pause()。这意味着您将不得不在信号处理程序内完成所有工作,这可能不是最好的事情,即,如果在下一个信号消失时您在信号处理程序内,您最终可能会得到如果您没有计划此类事件,则会出现一些不可预测的行为。

      更好的方法是执行以下操作:

      1) 设置一个信号掩码,在程序开始时阻止 SIGPROF。
      2) 不要使用信号处理程序来完成繁重的工作,而是使用 sigwait(),并使用包含 SIGPROF 掩码的 sigset_t 进行设置。
      3)通过以下方式设置程序的主要流程:

      sigset_t sigset;
      sigemptyset(&sigset);
      sigaddset(&sigset, SIGPROF);
      sigprocmask(SIG_BLOCK, &sigset, NULL); //block the SIGPROF signal
      
      //process your input
      
      //if you need to, initialize your timer and set it to go off
      
      while(SOME_FLAG_IS_TRUE) //maybe this loops forever ... depends on what you want?
      {
          sigwait(&sigset, &signal_num);
      
          if (signal_num != SIGPROF)
              continue;
      
          //process input ... 
      
          //... setup new interval timer with correct timeout ...
      
          //... repeat loop and/or exit loop or set flag to exit loop
      }
      

      这应该始终从间隔计时器捕获信号,因为 sigwait() 将在等待信号到达您的进程后正确返回,并且 SIGPROF 信号始终被阻止,这意味着您不能“丢失”信号.. . 相反,其中至少有一个将排队等待检测到对sigwait() 的下一次调用,以防万一在您的 while 循环中处理某些内容时有人到达。

      希望对你有帮助,

      杰森

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多