首先看它的作用:
一個進程的信號屏蔽字規定了當前阻塞而給該進程的信號集。調用函數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都會被接收處理.
另外, 當進程處於休眠狀態時, 當有信號發生時, 也會讓進程蘇醒過來, 這個接下來考慮一下。