linux信號--阻塞信號

1. 信號在內核中的表示

我們知道了信號產生的各種原因,而實際執行信號處理的動作,叫做信號遞達(Delivery)。信號從產生到遞達之間的狀態,稱爲信號未決(Pending)。進程可以選擇阻塞(Block)某個信號。被阻塞的信號產生時將保持在未決狀態,直到進程解除對此信號的阻塞,才執行遞達的動作。
 注意,阻塞和忽略是不同的,只要信號被阻塞就不會遞達,而忽略是在遞達之後可選的一種處理動作。
linux <wbr>--- <wbr>信號 <wbr>--- <wbr>阻塞信號:


 
 每個信號都有兩個標誌位分別表示阻塞和未決,,還有一個函數指針表示處理動作,信號產生時,內核在進程控制塊中設置該信號的未決標誌,直到信號遞達才清除該標誌。
(1) SIGHUP(簡記爲00):未阻塞未產生,處理動作遞達執行默認。
(2) SIGINT(簡記爲11):信號產生被阻塞,暫時不能遞達。處理動作是忽略,但在沒有解除阻塞之前不能忽略這個信號,因爲進程仍有機會改變處理動作之後再解除阻塞。
(3)SIGQUIT(10):未產生,一旦產生SIGQUIT信號將被阻塞,處理動作是用戶自定義函數sighandler。

 如果在進程解除對某信號的阻塞之前這種信號產生過多次,將如何處理?

 POSIX.1允許系統遞送該信號一次或多次。Linux是這樣實現的:普通信號在遞達之前產生多次只計一次,而實時信號在遞達之前產生多次可以依次放在一個隊列裏。
 從上圖來看,每個信號只有一個bit的未決標誌,非0即1,不記錄該信號產生了多少次,阻塞標誌也是這樣表示的。因此,未決和阻塞標誌可以用相同的數據類型sigset_t來存儲,sigset_t稱爲信號集,這個類型可以表示每個信號的“有效”或“無效”狀態,在阻塞信號集中“有效”和“無效”的含義是該信號是否被阻塞,而在未決信號集中“有效”和“無效”的含義是該信號是否處於未決狀態。
 即,只表示是否阻塞,不表示次數!
2. 信號集操作函數
 sigset_t類型對於每種信號用一個bit表示“有效”或“無效”狀態,至於這個類型內部如何存儲這些bit則依賴於系統實現,從使用者的角度是不必關心的,使用者只能調用以下函數來操作sigset_t變量,而不應該對它的內部數據做任何解釋,比如用printf直接打印sigset_t變量是沒有意義的。
 
 #include <signal.h>
int sigemptyset(sigset_t *set);  ----- 初始化set指向的信號集,使其中所有信號的對應bit清零,表示該信號集不包含任何有效信號.
int sigfillset(sigset_t *set); ---- 初始化set所指向的信號集,使其中所有信號的對應bit置位,表示該信號集的有效信號包括系統支持的所有信號。
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);判斷一個信號集的有效信號中是否包含某種信號,若包含則返回1,不含返回0,出錯返回-1,是一個布爾函數;
注意,在使用sigset_t類型的變量之前,一定要調用sigemptyset或sigfillset做初始化,使信號集處於確定的狀態。
 前四個函數都是成功返回0,出錯返回-1。
 
3. sigprocmask
調用函數sigprocmask可以讀取或更改進程的信號屏蔽字(阻塞信號集)

#include <signal.h>

int sigprocmask(int how,const siset_t *set,sigset_t *oset);

返回值:成功爲 0,出錯爲-1;
如果oset是非空指針,則讀取進程的當前信號屏蔽字通過oset參數傳出。如果set是非空指針,則更改進程的信號屏蔽字,參數how指示如何更改。如果oset和set都是非空指針,則先將原來的信號屏蔽字備份到oset裏,然後根據set和how參數更改信號屏蔽字。假設當前的信號屏蔽字爲mask,下表說明了how參數的可選值。
 linux <wbr>--- <wbr>信號 <wbr>--- <wbr>阻塞信號:


4、sigpending 

#include <signal.h>

int  sigpending (sigset_t * set)

sigpending 讀取當 前進程的未決信號集,通過set參數傳出,調用成功返回0,出錯返回-1;


5、代碼如下:

<span style="font-size:14px;">  1 #include <stdio.h>                                                                                          
  2 #include <signal.h>
  3 #include <unistd.h>
  4 
  5 void printsigset(sigset_t *set){   
  6     int i=0;
  7     for(;i<32;i++){
  8         if(sigismember(set,i)){
  9         putchar('1');
 10         }
 11         else{
 12         putchar('0');
 13         }
 14     }
 15     puts("");
 16 }
 17 int main()
 18 {
 19     sigset_t s,p;
 20     sigemptyset(&s);
 21     sigaddset(&s,SIGINT);
 22     sigprocmask(SIG_BLOCK,&s,NULL);
 23     while(1)
 24     {
 25         sigpending(&p);
 26         printsigset(&p);
 27         sleep(1);
 28     }
 29     return 0;
 30 }   </span>


結果如下:




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章