歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux技術 >> sigprocmask函數總結

sigprocmask函數總結

日期:2017/3/3 13:39:43   编辑:Linux技術

首先看它的作用:

一個進程的信號屏蔽字規定了當前阻塞而給該進程的信號集調用函數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都會被接收處理.

另外, 當進程處於休眠狀態時, 當有信號發生時, 也會讓進程蘇醒過來, 這個接下來考慮一下。

Copyright © Linux教程網 All Rights Reserved