【问题标题】:Simple Signals - C programming and alarm function简单信号 - C 编程和报警功能
【发布时间】:2009-11-23 16:07:46
【问题描述】:
#include  <stdio.h>
#include  <signal.h>


void  ALARMhandler(int sig)
{
  signal(SIGALRM, SIG_IGN);          /* ignore this signal       */
  printf("Hello");
  signal(SIGALRM, ALARMhandler);     /* reinstall the handler    */
}

int main(int argc, char *argv[])
{
  alarm(2);                     /* set alarm clock          */
  while (1)
    ;
  printf("All done");
}

我希望程序在 2 秒后打印“hello”,但输出却是“zsh: alarm ./a.out”

知道发生了什么吗?

【问题讨论】:

    标签: c signals


    【解决方案1】:

    您最初忘记设置警报处理程序。将main()的开头改为:

    int main(int argc, char *argv[])
    {
       signal(SIGALRM, ALARMhandler);
       ...
    

    此外,信号处理程序可能不会打印任何内容。这是因为 C 库会缓存输出,直到看到行尾。所以:

    void  ALARMhandler(int sig)
    {
      signal(SIGALRM, SIG_IGN);          /* ignore this signal       */
      printf("Hello\n");
      signal(SIGALRM, ALARMhandler);     /* reinstall the handler    */
    }
    

    对于现实世界的程序,从信号处理程序打印不是很安全。信号处理程序应该尽可能少做,最好只在这里或那里设置一个标志。并且标志应该被声明为volatile。

    【讨论】:

    • 真实示例:我曾经在一个使用 Access 数据库作为后端的系统上工作,在某些情况下,信号处理程序中的 printf() 调用会写入 .mdb 文件标准输出,使数据库无法修复。
    【解决方案2】:

    您没有在 main 函数中设置处理程序。

    在您执行alarm(2) 之前,请将signal(SIGALRM, ALARMhandler); 放入您的main。

    那么它应该可以工作了。

    请注意,您的“All Done”永远不会被打印出来,因为在信号处理器运行后您将停留在 while(1) 循环中。如果你想打破循环,你需要有一个信号处理程序改变的标志。

    #include <stdio.h>
    #include <signal.h>
    #include <unistd.h>
    
    /* number of times the handle will run: */
    volatile int breakflag = 3;
    
    void handle(int sig) {
        printf("Hello\n");
        --breakflag;
        alarm(1);
    }
    
    int main() {
        signal(SIGALRM, handle);
        alarm(1);
        while(breakflag) { sleep(1); }
        printf("done\n");
        return 0;
    }
    

    【讨论】:

    • +1 对于漂亮的程序。我认为您必须在信号处理程序中调用alarm(2):通常一个alarm() 调用只会生成一个SIGALRM
    • 当然,你是对的。我显然没有测试这段代码,也有一段时间没有以这种方式使用信号了(值得注意的是,它们在线程环境中以这种方式使用是无用的)。
    • 为 breakflag 变量提供 volatile 存储类有什么需要?
    • volatile 旨在防止编译器优化存储或加载,因此代码执行的两个不同部分(主循环、信号处理程序)始终正确地看到另一部分的值。但是,我对这段代码的正确性没有信心,我可能会改用原子代码。
    • 添加#include &lt;unistd.h&gt;,去掉函数‘alarm’和‘sleep’隐式声明的警告信息
    【解决方案3】:

    您没有先安装信号处理程序。
    您需要在实际接收信号之前告诉系统您要处理信号,因此您需要在信号到来之前从 main 调用signal()。

    int main(int argc, char *argv[])
    {
      signal(SIGALRM, ALARMhandler);     /* install the handler    */
      alarm(2);                     /* set alarm clock          */
      while (1);
    }
    

    【讨论】:

      【解决方案4】:

      安多玛是正确的。我对此进行测试, 版本 1 打印(每秒):

      Hi...
      Hi...
      Hi...
      Hi...
      BYE
      Hi...
      ...
      

      第 2 版打印(每五秒一次):

      Hi...Hi...Hi...Hi...BYE
      Hi...Hi...Hi...Hi...BYE
      ...
      

      所以代码是:

      #include <stdio.h>
      #include <unistd.h>
      #include <signal.h>
      
      # define T 5
      
      int flag = T;
      
      void sigalrm_handler(int);
      
      int  main(void)
      {
          signal(SIGALRM, sigalrm_handler);   
          alarm(1);                         
          while (1);  
      }
      
      void sigalrm_handler(int sig)
      {
          if(--flag){
              printf("Hi...\n");   /*version 1*/
              /*printf("Hi...");*/ /*version 2*/
          }else{
              printf("BYE\n");
              flag=T;     
          }
          alarm(1);
      }
      

      【讨论】:

      • 感谢您提供完整且有效的代码。我只是将它粘贴到我现有程序的 main{} 顶部并启动它。
      猜你喜欢
      • 1970-01-01
      • 2021-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多