首先看它的作用:
一個進程的信號屏蔽字規定了當前阻塞而給該進程的信號集。調用函數sigprocmask可以檢測或更改其信號屏蔽字,或者在一個步驟中同時執行這兩個操作。
#include <signal.h> int sigprocmask( int how, const sigset_t *restrict set, sigset_t *restrict oset ); 返回值:若成功則返回0,若出錯則返回-1
首先,若oset是非空指針,那麼進程的當前信號屏蔽字通過oset返回。其次,若set是一個非空指針,則參數how指示如何修改當前信號屏蔽字。
表10-4說明了how可選用的值。注意,不能阻塞SIGKILL和SIGSTOP信號。表10-4 用sigprocmask更改當前信號屏蔽字的方法
how 說明SIG_BLOCK該進程新的信號屏蔽字是其當前信號屏蔽字和set指向信號集的並集。set包含了我們希望阻塞的附加信號SIG_UNBLOCK該進程新的信號屏蔽字是其當前信號屏蔽字和set所指向信號集補集的交集。set包含了我希望解除阻塞的信號SIG_SETMASK該進程新的信號屏蔽字將被set指向的信號集的值代替如果set是空指針,則不改變該進程的信號屏蔽字,how的值也無意義。
在調用sigprocmask後如果有任何未決的、不再阻塞的信號,則在sigprocmask返回前,至少會將其中一個信號遞送給該進程。
尤其注意最後這句話!!! 接下來我來說明為什麼寫這篇博客
我們知道, 當造成信號的事件發生,比如硬件異常(如除以0),軟件條件(如alarm計時器超時)、終端產生的信號或調用kill函數產生的信號,內核向進程發送一個信號。當我們連續多次產生同一個信號,比如SIGINT信號,
系統究竟是只接受第一個而屏蔽了以後多個信號呢?還是都接收信號?我們當且敢肯定的是第一個信號是會被接收(在sigprocmask中沒有屏蔽這個信號)的。此時,調用進程會轉到信號處理程序中, 因為我們可以用sigprocmask來檢測當前進程的信號屏蔽字的,所以我們就可以在信號處理程序中來查看此信號是否被屏蔽了。
所以我們來看一段代碼,代碼意思就是檢測SIGINT信號, 當發生信號後轉到sig_int(int) 函數中, 在pr_mask函數中,使用了sigprocmask函數來檢測當前進程是否屏蔽了SIGINT信號:
#include <stdio.h> #include <signal.h> void sig_int( int ); void pr_mask( const char *); //call to funtion pr_mask int main(int argc , char *argv[]){ setbuf( stdout , NULL ); //close buffer pr_mask( "before catching signal ,mask sig :" ); if( signal( SIGINT , sig_int ) == SIG_ERR ) oops( "signal" ); //keep loop to catch signal interuption while(1) // pause(); sleep( 3 ); pr_mask( "end catching signal ,mask sig :" ); return 0; } //signal handler void sig_int( int signo ){ pr_mask( "in signal handler:" ); }pr_mask函數和oops函數如下:
#include <stdio.h> #include <errno.h> #include <signal.h> void pr_mask( const char *str ){ sigset_t set; int errno_save; //get the pre errno errno_save = errno; if( sigprocmask( 0, NULL , &set ) == -1 ) oops( " sigmask" ); else{ printf( "\n%s" , str ); if( sigismember( &set , SIGQUIT ) ) printf( " SIGQUIT" ); if( sigismember( &set , SIGINT ) ) printf( " SIGINT" ); if( sigismember( &set , SIGUSR1 ) ) printf( " SIGUSR1" ); if( sigismember( &set , SIGALRM ) ) printf( " SIGALRM" ); } errno = errno_save ; }
#include <stdio.h> #include <stdlib.h> void oops(void *msg){ perror(msg); exit(1); }
接下來我們看看結果:
這裡結果就出乎我的預料了。首先在沒有按下ctrl+c產生SIGINT信號前, 進程中沒有屏蔽SIGINT信號,而當我們產生中斷信號是,由結果可以看到SIGINT信號被屏蔽了,但出人意料的是當我們多次產生中斷信號的時候, 進程全部都接收了。 現在再讀讀
在調用sigprocmask後如果有任何未決的、不再阻塞的信號,則在sigprocmask返回前,至少會將其中一個信號遞送給該進程。
也就是說,因為程序中我們並沒有屏蔽中斷信號,而當進程在處理中斷信號的時候是屏蔽了接下來的中斷信號,所以在信號處理函數中會有SIGINT出現, 而當信號處理函數完成,准確的說是sigprocmask完成前, 接下來的SIGINT都會被接收處理.
另外, 當進程處於休眠狀態時, 當有信號發生時, 也會讓進程蘇醒過來, 這個接下來考慮一下。