咱们已经知道,咱们能够经过信号来终止进程,也能够经过信号来在进程间进行通讯,程序也能够经过指定信号的关联处理函数来改变信号的默认处理方式,也能够屏蔽某些信号,使其不能传递给进程。那么咱们应该如何设定咱们须要处理的信号,咱们不须要处理哪些信号等问题呢?信号集函数就是帮助咱们解决这些问题的。php
有关Linux进程间使用信号通讯的更多内容,能够参阅个人另外一篇文章,Linux进程间通讯 -- 信号量函数 signal()、sigaction()html
下面是信号函数集:编程
一、int sigemptyset(sigset_t *set);服务器
该函数的做用是将信号集初始化为空。app
二、int sigfillset(sigset_t *set);函数
该函数的做用是把信号集初始化包含全部已定义的信号。性能
三、int sigaddset(sigset_t *set, int signo);测试
该函数的做用是把信号signo添加到信号集set中,成功时返回0,失败时返回-1。ui
四、int sigdelset(sigset_t *set, int signo);spa
该函数的做用是把信号signo从信号集set中删除,成功时返回0,失败时返回-1.
五、int sigismember(sigset_t *set, int signo);
该函数的做用是判断给定的信号signo是不是信号集中的一个成员,若是是返回1,若是不是,返回0,若是给定的信号无效,返回-1;
六、int sigpromask(int how, const sigset_t *set, sigset_t *oset);
该函数能够根据参数指定的方法修改进程的信号屏蔽字。新的信号屏蔽字由参数set(非空)指定,而原先的信号屏蔽字将保存在oset(非空)中。若是set为空,则how没有意义,但此时调用该函数,若是oset不为空,则把当前信号屏蔽字保存到oset中。
how 的不一样取值及操做以下所示:
若是sigpromask成功完成返回0,若是how取值无效返回-1,并设置errno为EINVAL。
注意:调用这个函数才能改变进程的屏蔽字,以前的函数都是为改变一个变量的值而已,并不会真正影响进程的屏蔽字。
七、int sigpending(sigset_t *set);
该函数的做用是将被阻塞的信号中停留在待处理状态的一组信号写到参数set指向的信号集中,成功调用返回0,不然返回-1,并设置errno代表错误缘由。
八、int sigsuspend(const sigset_t *sigmask);
该函数经过将进程的屏蔽字替换为由参数sigmask给出的信号集,而后挂起进程的执行。注意操做的前后顺序,是先替换再挂起程序的执行。程序将在信号处理函数执行完毕后继续执行。若是接收到信号终止了程序,sigsuspend()就不会返回,若是接收到的信号没有终止程序,sigsuspend()就返回-1,并将errno设置为EINTR。
特别提醒:若是一个信号被进程阻塞,它就不会传递给进程,但会停留在待处理状态,当进程解除对待处理信号的阻塞时,待处理信号就会马上被处理。
下面以一个例子来讲明上述函数的用法,源文件为 sigset.c,代码以下:
#include <stdio.h> #include <signal.h> #include <unistd.h> void handler(int sig) { printf("Handle the signal %d\n", sig); } int main(int argc, char **argv) { sigset_t sigset; // 用于记录屏蔽字 sigset_t ign; // 用于记录被阻塞(屏蔽)的信号集 struct sigaction act; // 清空信号集 sigemptyset(&sigset); sigemptyset(&ign); // 向信号集中添加 SIGINT sigaddset(&sigset, SIGINT); // 设置处理函数 和 信号集 act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, 0); printf("Wait the signal SIGNAL...\n"); pause(); // 设置进程屏蔽字, 在本例中为屏蔽 SIGINT sigprocmask(SIG_SETMASK, &sigset, 0); printf("Please press Ctrl + C in 10 seconds...\n"); sleep(10); // 测试 SIGINT 是否被屏蔽 sigpending(&ign); if (sigismember(&ign, SIGINT)) { printf("The SIGINT signal has ignored\n"); } // 从信号集中删除信号 SIGINT sigdelset(&sigset, SIGINT); printf("Wait the signal SIGINT...\n"); // 将进程的屏蔽字从新设置, 即取消对 SIGINT 的屏蔽 // 并挂起进程 sigsuspend(&sigset); printf("The app will exit in 5 secondes!\n"); sleep(5); return 0; }
运行结果以下:
首先,咱们能过sigaction()函数改变了SIGINT信号的默认行为,使之执行指定的函数handler,因此输出了语句:Handle the signal 2。而后,经过sigprocmask()设置进程的信号屏蔽字,把SIGINT信号屏蔽起来,因此过了10秒以后,用sigpending()函数去获取被阻塞的信号集时,检测到了被阻塞的信号SIGINT,输出The SIGINT signal has ignored。最后,用函数sigdelset()函数去除先前用sigaddset()函数加在sigset上的信号SIGINT,再调用函数sigsuspend(),把进程的屏蔽字再次修改成sigset(不包含SIGINT),并挂起进程。因为先前的SIGINT信号停留在待处理状态,而如今进程已经再也不阻塞该信号,因此进程立刻对该信号进行处理,从而在最后,你不用输入 Ctrl+C 也会出现后面的处理语句(可参阅前面特别提醒的内容),最后过了5秒程序就成功退出了。
参考:
http://blog.csdn.net/ljianhui/article/details/10130539
《Linux 高性能服务器编程》