歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

《APUE》:信號處理

《Unix環境高級編程》這本書附帶了許多短小精美的小程序,我在閱讀此書的時候,將書上的代碼按照自己的理解重寫了一遍(大部分是抄書上的),加深一下自己的理解(純看書太困了,呵呵)。此例子在Ubuntu 10.04上測試通過。

相關鏈接

  • 《UNIX環境高級編程》(第二版)apue.h的錯誤 http://www.linuxidc.com/Linux/2011-04/34662.htm
  • Unix環境高級編程 源代碼地址 http://www.linuxidc.com/Linux/2011-04/34826.htm

程序簡介:在Unix環境下,我們可以讓程序屏蔽掉某些信號(SIGKILL信號和SIGSTOP除外),這個例子演示了這方面的功能。

  1. //《APUE》程序10-11:信號處理和sigprocmask實例   
  2. #include <unistd.h>   
  3. #include <stdio.h>   
  4. #include <stdlib.h>   
  5. #include <signal.h>   
  6.   
  7. //輸出錯誤信息並退出       
  8. void error_quit(const char *str)      
  9. {      
  10.     fprintf(stderr, "%s\n", str);      
  11.     exit(1);      
  12. }    
  13.   
  14. //SIGQUIT信號的處理函數   
  15. void sig_quit(int signo)  
  16. {  
  17.     printf("caught SIGQUIT\n");  
  18.     if( SIG_ERR == signal(SIGQUIT, SIG_DFL) )  
  19.         error_quit("can't reset SIGQUIT");  
  20. }  
  21.   
  22. int main(void)  
  23. {  
  24.     sigset_t newmask, oldmask, pendmask;  
  25.     //設置對SIGQUIT信號的處理函數   
  26.     if( SIG_ERR == signal(SIGQUIT, sig_quit) )  
  27.         error_quit("can't catch SIGQUIT");  
  28.   
  29.     //將newmask信號集初始化為空   
  30.     sigemptyset(&newmask);  
  31.     //在newmask信號集中增加SIGQUIT信號   
  32.     sigaddset(&newmask, SIGQUIT);  
  33.   
  34.     int temp;  
  35.     //將oldmask設置為當前的屏蔽信號集(方便以後恢復)   
  36.     //在當前的屏蔽信號添加增加newmask信號集   
  37.     temp = sigprocmask(SIG_BLOCK, &newmask, &oldmask);  
  38.     if( temp < 0 )  
  39.         error_quit("SIG_BLOCK error");  
  40.   
  41.     sleep(5);  
  42.   
  43.     //返回當前的屏蔽信號集     
  44.     temp = sigpending(&pendmask);  
  45.     if( temp < 0 )  
  46.         error_quit("sigpending error");  
  47.     //檢查SIGQUIT信號是否在pendmask信號集中   
  48.     if( sigismember(&pendmask, SIGQUIT) )  
  49.         printf("\nSIGQUIT pending\n");  
  50.   
  51.     //恢復屏蔽信號集   
  52.     temp = sigprocmask(SIG_SETMASK, &oldmask, NULL);  
  53.     if( temp < 0 )  
  54.         error_quit("SIG_SETMASK error");  
  55.     printf("SIGQUIT unblocked\n");  
  56.   
  57.     sleep(5);  
  58.     return 0;  
  59. }  

運行示例:

www.linuxidc.com @ubuntu:~/code$ gcc temp.c -o temp 
www.linuxidc.com @ubuntu:~/code$ ./temp 
^\              #產生一次SIGQUIT信號 
SIGQUIT pending         #從sleep返回後 
caught SIGQUIT          #在信號處理程序中 
SIGQUIT unblocked       #從sigpromask返回後 
^\退出                #再次產生信號 
 
www.linuxidc.com @ubuntu:~/code$ ./temp   #再次運行程序 
^\^\^\^\^\^\^\^\^\^\^\^\    #產生多次SIGQUIT信號 
SIGQUIT pending  
caught SIGQUIT          #只接收到一次信號 
SIGQUIT unblocked 
^\退出 

結論:

1:進程阻塞了SIGQUIT信號,在此期間所產生的SIGQUIT信號都會被阻塞,直到該信號不再被阻塞。

2:在休眠期間,如果產生了信號,那麼此時的信號是未決的,但是不再受阻塞(所以在退出之前,sig_quit函數可以被調用)

3:在信號被阻塞期間系統不會對信號進行排隊。

注解(這段話是從網上摘抄的):

信號的”未決“是一種狀態,指的是從信號的產生到信號被處理前的這一段時間;信號的”阻塞“是一個開關動作,指的是阻止信號被處理,但不是阻止信號產生。

APUE例題在sleep前用sigprocmask阻塞了退出信號,然後sleep,然後在sleep的過程中產生一個退出信號,但是此時退出信號被阻塞過,(中文的”阻塞”在這裡容易被誤解為一種狀態,實際上是一種類似於開關的動作,所以說“被阻塞過”,而不是“被阻塞”)所以處於“未決”狀態,在 sleep後又用sigprocmask關掉退出信號的阻塞開關,因為之前產生的退出信號一直處於未決狀態,當關上���塞開關後,馬上退出“未決”狀態,得到處理,這一切發生在sigprocmask返回之前。

Copyright © Linux教程網 All Rights Reserved