簡體   English   中英

到達雙精度SIGINT時終止主程序和所有fork的信號處理程序

[英]signal handler to terminate the main program and all forks when arrives a double SIGINT

我真的不知道信號處理程序如何工作,尤其是在使用分叉時。 所以我需要做這個練習,但是我無法正常工作。

我的主程序制作了5個fork,每個fork的pid僅打印10條消息。 因此,該程序的目的是,當我通過鍵盤(Ctrl-c)發送SIGINT信號時,它應該打印“單個SIGINT到達”,如果兩個SIGINT在1秒鍾之間到達,則應打印“ double SIGINT到達”並終止整個程序。 因此,當我啟動程序時,它將處理前兩個SIGINT(我將第一個發送的第二個SIGINT發送超過第二個SIGINT),但隨后它不處理單個SIGINT和兩個SIGINT。

所以我對信號非常困惑。 叉繼續標記郵件。 我將相同的處理程序加載到main和fork中,但是當到達double SIGINT時我應該怎么做才能終止所有fork? 我應該在處理程序中調用killl或其他函數來終止它們嗎?

主要功能

 /* libraries... */

 volatile sig_atomic_t double_sigint = 0;
 int64_t time_diff = 0;

 int main()
 {
  int i;
  int pid;

  sigset_t set;
  struct sigaction sa;


         /* mask all signals */ 
 /*H*/   if(sigfillset(&set) == -1 )
 /*A*/     {perror("sigfillset"); exit(errno);} 
 /*N*/  
 /*D*/   if(sigprocmask(SIG_SETMASK,&set,NULL) == -1)
 /*L*/     {perror("sigfillset"); exit(errno);} 
 /*E*/       
 /*R*/   memset(&sa,0,sizeof(sa));
 /*B*/   
 /*L*/   sa.sa_handler = handler;
 /*O*/   
 /*C*/   if(sigaction(SIGINT, &sa, NULL) == -1)
 /*K*/         {perror("sigaction"); exit(errno);}
 /**/   
 /**/    /* unmask all signals */
 /**/    if( sigemptyset(&set) == -1 )
 /**/      {perror("sigepmtyset"); exit(errno);}
 /**/   
 /**/    if(sigprocmask(SIG_SETMASK,&set,NULL) == -1 )
 /**/        {perror("sigprocmask"); exit(errno);}



  for(i=0;i<5;++i)
  {
    if((pid = fork()) == -1)
      { perror("rec:fork"); exit(errno); }

    if(pid == 0)/* figlio */
    {

      /* SAME HANDLER BLOCK IS HERE */        

      foo(i);

      return;

    }
    sleep(1);
  }

  return 0;
 }

foo函數

 void foo(int i)
{
  int k;

  for(k=0; k<10; ++k)
  {
    printf("%d. fork %d. print\n", i, k);
    sleep(1);
  }
}

信號處理器

  void handler (int signum) {

  struct timespec sig1;
  struct timespec sig2;

  if(double_sigint == 0)
  {
    if(clock_gettime(CLOCK_REALTIME, &sig1))
      { perror("failed to get sig1 time"); exit(errno); }

    write(1,"Received single SIGINT\n",18);

    double_sigint = 1;

  }
  else if(double_sigint == 1)
  {
     if(clock_gettime(CLOCK_REALTIME, &sig2))
       { perror("failed to get sig2 time"); exit(errno); }

     time_diff = (sig2.tv_sec - sig1.tv_sec) + (sig2.tv_nsec - sig1.tv_nsec)/1000000000;

     if(time_diff < 1)
     {
       double_sigint = 2;  
       write(1,"Received double SIGINT\n",18);
       _exit(EXIT_FAILURE);

     }
     else
     {
      sig1.tv_sec = sig2.tv_sec;
      sig1.tv_nsec = sig2.tv_nsec;

      write(1,"Received single SIGINT\n",18);

     }

  }

}

當您收到一個雙SIGINT時,您只用行_exit(EXIT_FAILURE);殺死父進程_exit(EXIT_FAILURE); 您之前創建的fork不會被殺死並繼續運行,它們的父級現在是init進程。

如果要終止所有孩子,則必須手動殺死他們。 也許這篇文章會有所幫助: 如何使子進程在父母退出后死亡

編輯:這不是問題,因為Ctrl + C將SIGINT發送給所有子級(請參閱注釋)。 對我有用的是:

  • 如William Pursell的評論所述,使sig1和sig2全局變量。
  • 使父進程始終運行(在return語句之前添加一小段while (1);因為在父進程終止后不會考慮某些信號)。

在處理程序中,在else子句(double_sigint == 1)中,您正在比較sig2和sig1,但是sig1未初始化。 當處理程序返回時,您第一次給處理程序調用的值消失了。 您可以簡單地為這些變量提供文件作用域。

通過使用局部變量的未初始化值,您將獲得未定義的行為。 如果調用了信號處理程序,並且信號處理堆棧恰好與上一次調用處於同一狀態,則可能工作正常。 例如,如果您兩次發送信號而沒有中間信號,則會發生這種情況。 由於睡眠可能是通過信號實現的,因此很可能堆棧已被修改,因為上一次調用和sig1不是您所期望的。 但是,關於未定義行為的猜測是沒有意義的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM