🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # 信号集 ## 自定义信号集函数 为了方便对多个信号进行处理,一个用户进程常常需要对多个信号做出处理,在 Linux 系统中引入了信号集(信号的集合)。 这个信号集有点类似于我们的 QQ 群,一个个的信号相当于 QQ 群里的一个个好友。 信号集是一个能表示多个信号的数据类型,sigset\_t set,set即一个信号集。既然是一个集合,就需要对集合进行添加/删除等操作。 ~~~ #include <signal.h> ​ int sigemptyset(sigset_t *set); //将set集合置空 int sigfillset(sigset_t *set); //将所有信号加入set集合 int sigaddset(sigset_t *set, int signo); //将signo信号加入到set集合 int sigdelset(sigset_t *set, int signo); //从set集合中移除signo信号 int sigismember(const sigset_t *set, int signo); //判断信号是否存在 ~~~ 除sigismember外,其余操作函数中的set均为传出参数。sigset\_t类型的本质是位图。但不应该直接使用位操作,而应该使用上述函数,保证跨系统操作有效。 ~~~ int main() { sigset_t set; // 定义一个信号集变量 int ret = 0; ​ sigemptyset(&set); // 清空信号集的内容 ​ // 判断 SIGINT 是否在信号集 set 里 // 在返回 1, 不在返回 0 ret = sigismember(&set, SIGINT); if (ret == 0) { printf("SIGINT is not a member of set \nret = %d\n", ret); } ​ sigaddset(&set, SIGINT); // 把 SIGINT 添加到信号集 set sigaddset(&set, SIGQUIT);// 把 SIGQUIT 添加到信号集 set ​ // 判断 SIGINT 是否在信号集 set 里 // 在返回 1, 不在返回 0 ret = sigismember(&set, SIGINT); if (ret == 1) { printf("SIGINT is a member of set \nret = %d\n", ret); } ​ sigdelset(&set, SIGQUIT); // 把 SIGQUIT 从信号集 set 移除 ​ // 判断 SIGQUIT 是否在信号集 set 里 // 在返回 1, 不在返回 0 ret = sigismember(&set, SIGQUIT); if (ret == 0) { printf("SIGQUIT is not a member of set \nret = %d\n", ret); } ​ return 0; } ~~~ ## sigprocmask函数 信号阻塞集也称信号屏蔽集、信号掩码。每个进程都有一个阻塞集,创建子进程时子进程将继承父进程的阻塞集。信号阻塞集用来描述哪些信号递送到该进程的时候被阻塞(在信号发生时记住它,直到进程准备好时再将信号通知进程)。 所谓阻塞并不是禁止传送信号, 而是暂缓信号的传送。若将被阻塞的信号从信号阻塞集中删除,且对应的信号在被阻塞时发生了,进程将会收到相应的信号。 我们可以通过 sigprocmask() 修改当前的信号掩码来改变信号的阻塞情况 ~~~ #include <signal.h> ​ int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); 功能: 检查或修改信号阻塞集,根据 how 指定的方法对进程的阻塞集合进行修改,新的信号阻塞集由 set 指定,而原先的信号阻塞集合由 oldset 保存。 ​ 参数: how : 信号阻塞集合的修改方法,有 3 种情况: SIG_BLOCK:向信号阻塞集合中添加 set 信号集,新的信号掩码是set和旧信号掩码的并集。相当于 mask = mask|set。 SIG_UNBLOCK:从信号阻塞集合中删除 set 信号集,从当前信号掩码中去除 set 中的信号。相当于 mask = mask & ~ set。 SIG_SETMASK:将信号阻塞集合设为 set 信号集,相当于原来信号阻塞集的内容清空,然后按照 set 中的信号重新设置信号阻塞集。相当于mask = set。 set : 要操作的信号集地址。 若 set 为 NULL,则不改变信号阻塞集合,函数只把当前信号阻塞集合保存到 oldset 中。 oldset : 保存原先信号阻塞集地址 ​ 返回值: 成功:0, 失败:-1,失败时错误代码只可能是 EINVAL,表示参数 how 不合法。 ~~~ ## sigpending函数 ~~~ ​#include <signal.h> ​ int sigpending(sigset_t *set); 功能:读取当前进程的未决信号集 参数: set:未决信号集 返回值: 成功:0 失败:-1 ~~~ ~~~ int main() { // 自定义信号集 sigset_t myset, old; sigemptyset(&myset);// 清空 -》 0 ​ // 添加要阻塞的信号 sigaddset(&myset, SIGINT); sigaddset(&myset, SIGQUIT); sigaddset(&myset, SIGKILL); ​ // 自定义信号集设置到内核中的阻塞信号集 sigprocmask(SIG_BLOCK, &myset, &old); ​ sigset_t pend; int i = 0; while (1) { // 读内核中的未决信号集的状态 sigpending(&pend); for (int i = 1; i<32; ++i) { if (sigismember(&pend, i)) { printf("1"); } else if (sigismember(&pend, i) == 0) { printf("0"); } } printf("\n"); sleep(1); i++; ​ // 10s之后解除阻塞 if (i > 10) { // sigprocmask(SIG_UNBLOCK, &myset, NULL); sigprocmask(SIG_SETMASK, &old, NULL); } } ​ return 0; } ~~~