1 #include<signal.h> 2 int sigsuspend(const sigset_t *sigmask); 3 返回值:-1,并将errno设置为EINTR
将进程的信号屏蔽字设置为由sigmask指向的值,在捕捉到一个信号或发生了一个会终止该进程的信号之前,该进程被挂起。
例子:
利用sigsuspend函数阻塞子进程;
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<signal.h> 4 #include<unistd.h> 5 6 sig_atomic_t sigflag; 7 sigset_t newmask,oldmask,zeromask; 8 9 void sig_int(int signo) 10 { 11 sigflag = 1; 12 } 13 14 void tell_wait(void) 15 { 16 sigflag = 0; 17 if(signal(SIGUSR1,sig_int) == SIG_ERR){ 18 printf("signal error! "); 19 exit(1); 20 } 21 printf("after signal! "); 22 /* 23 sigemptyset(&newmask); 24 sigemptyset(&zeromask); 25 sigaddset(&newmask,SIGINT); 26 if(sigprocmask(SIG_BLOCK,&newmask,&oldmask) < 0){ 27 printf("sigprocmask error! "); 28 exit(1); 29 } 30 */ 31 } 32 33 void tell_child(pid_t pid) 34 { 35 kill(pid,SIGUSR1); 36 } 37 38 void wait_parent(void) 39 { 40 while(sigflag == 0) 41 sigsuspend(&zeromask); 42 43 sigflag = 0; 44 45 if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0){ 46 printf("sigprocmask erro! "); 47 exit(1); 48 } 49 } 50 51 int main(int argc, char *argv[]) 52 { 53 pid_t pid; 54 55 printf("before signal! "); 56 57 tell_wait(); 58 59 if((pid = fork()) < 0){ 60 printf("fork error! "); 61 exit(1); 62 } 63 else if(pid == 0){ 64 wait_parent(); 65 printf("this is child! "); 66 exit(0); 67 } 68 else{ 69 printf("this is parent! "); 70 tell_child(pid); 71 } 72 exit(0); 73 }
例子中的sigprocmask函数是用来检测或更改其信号屏蔽字,或者在一个步骤中同时执行这两个操作。
#include<signal.h> int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset); //返回值:成功返回0,出错返回-1
how: SIG_BLOCK SIG_UNBLOCK SIG_SETMASK
sigprocmask配合sigpending函数使用,
#include<signal.h> int sigpending(sigset_t *set); //返回值:成功返回0,出错返回-1
sigpending函数:查询被搁置的信号!
其实sigsuspend是一个原子操作,包含4个步骤:
(1) 设置新的mask阻塞当前进程;
(2) 收到信号,恢复原先mask;
(3) 调用该进程设置的信号处理函数;
(4) 待信号处理函数返回后,sigsuspend返回。
pause函数和sigsuspend函数的区别:
简单的说, sigsuspend = unblock + pause
sigsuspend 函数是用于需要先接触 某个信号的阻塞状态 然后等待该信号发生 这样的应用场景; 而使用 pause 在达到这样的效果时肯定是需要先 调用sigprocmask进行取消阻塞,再调用pause去等待,取消阻塞与等待两步之间有时间窗口,在信号发生在调用pause之前任意时刻的话都有可能导致pause之后再也收不到该信号,也就是永远休眠。为了解决这种情况,sigsuspend函数把这两步做成一个原子操作,这就保证不会丢失(错过)信号,也就不会发生永远休眠这种情况(根本不发生该信号时除外)。所以,建议只用sigsuspend去等待信号。