在Linux服务端后台开发中,经常会用到信号处理函数:sigprocmask
和sigsuspend
。这篇文章主要通过一个综合实例演示如何使用sigprocmask函数屏蔽目标信号(信号掩码)以及sigsuspend函数挂起进程。
关于sigprocmask
函数的说明:
头文件: #include <signal.h>
函数: int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
功能: 用于获取或者改变当前进程的信号掩码(当前进程屏蔽的信号集)。
返回值: 0成功,-1失败(具体原因由errno值表示)。
关于sigsuspend
函数的说明:
头文件: #include <signal.h>
函数: int sigsuspend(const sigset_t *mask);
功能: 阻塞当前进程(TASK_INTERRUPTIBLE可中断状态),等待mask信号集(信号掩码)之外的任何信号的到来。
在收到pendmask之外)信号后,先调用该信号的处理函数,然后把信号集mask还原为原来的信号集,接着从sigsuspend调用处返回(进程恢复执行)。
返回值: 该系统调用始终返回-1,并将errno设置为EINTR。
在CentOS服务器中使用编译并执行下面这段程序,效果如上图所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | /** * @FileName sigprocmask_sigsuspend.c * @Describe A simple example for using sigprocmask and sigsuspend functions in linux. * @Author vfhky 2016-02-29 11:21 https://typecodes.com/cseries/sigprocmasksigsuspendapp.html * @Compile gcc sigprocmask_sigsuspend.c -o sigprocmask_sigsuspend */ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <signal.h> #include <errno.h> //Signal handle function. void sig_handler( int signal ) { printf( "Receive signal=%d.\n", signal ); return; } int main( int argc, char *argv[] ) { printf( "getpid=%d.\n", getpid() ); int i = 0; //Register a signal. struct sigaction new_act; sigemptyset( &new_act.sa_mask ); new_act.sa_handler = sig_handler; new_act.sa_flags = 0; sigaction( SIGUSR1, &new_act, 0 ); sigaction( SIGUSR2, &new_act, 0 ); sigaction( SIGINT, &new_act, 0 ); //Add SIGINT, SIGUSR1/SIGUSR2 signals to the signal-set of new_set. sigset_t new_set, old_set; sigemptyset( &new_set ); sigaddset( &new_set, SIGINT ); //2 sigaddset( &new_set, SIGUSR1 ); //10 //sigaddset( &new_set, SIGUSR2 ); //12 /** * Repalce the old mask set with the new mask set.Thus the process will block the signal of SIGINT and SIGUSR1, * but it will excute the function of sig_handler when the signal such as SIGUSR2 other than SIGINT, SIGUSR1 arrives. */ sigprocmask( SIG_SETMASK, &new_set, &old_set ); //Add SIGUSR1 and SIGUSR2 signals to the signal-set of pendmask. sigset_t pendmask; sigemptyset( &pendmask ); sigaddset( &pendmask, SIGUSR1 ); //10 sigaddset( &pendmask, SIGUSR2 ); //12 //Replaces the signal mask of the process with pendmask temporarily and suspends the process until delivery of a signal whose action is to invoke a signal handler or to terminate a process. i = sigsuspend( &pendmask ); printf( "Sigsuspend returned with value%d.\n", i ); if( errno == EINTR ) { printf( "%dInterrupted by a signal.\n", errno ); } while(1) { printf( "--while.\n" ); sleep(3); } return 0; } |
---|
如下图所示,使用kill
命令向进程(PID:7154)发送SIGUSR1
和SIGUSR2
信号。
由于sigsuspend
函数把信号SIGUSR1
和SIGUSR2
加入到信号掩码pendmask
中,所以这两个信号的到来对当前进程没有任何影响。
使用命令kill -SIGINT 7154
向当前进程(PID:7154)发送SIGINT
信号。由于该信号不在信号掩码pendmask
中,所以先调用SIGINT
信号的处理函数sig_handler,然后把现在的信号集pendmask
还原为原来的new_set
信号集。
这时,由于之前由于信号掩码pendmask
被屏蔽的未决信号信号SIGUSR1
和SIGUSR2
由内核重新传递,所以进程会执行SIGUSR2
信号的处理函数(SIGUSR1信号被信号集new_set所屏蔽,因此不会执行)。接着进程从sigsuspend调用处返回,恢复执行(进入while循环)。
如果继续发送SIGINT
信号,因为被加入到了当前信号掩码new_set
中,所以也会被屏蔽(对进程无影响)。最后可以通过命令kill -SIGKILL 7154
将整个进程关闭。