操作系统信号集与信号屏蔽
信号集与信号屏蔽
什么是信号集:
-
是一种专门用于存储多个信号的数据类型 sigset_t
-
该类型占128字节,每个字节代表了一种信号的有或无
操作信号集的相关函数:
int sigemptyset(sigset_t *set); 功能:将信号集set中的所有信号置零 清空信号集 int sigfillset(sigset_t *set); 功能:把信号集set中所有信号置1 int sigaddset(sigset_t *set, int signum); 功能:将信号集set中的信号signum置1 int sigdelset(sigset_t *set, int signum); 功能:将信号集set中的信号signum置0 int sigismember(const sigset_t *set, int signum); 功能:测试信号集中是否存在signum信号 返回值:存在返回1, 不存在返回0 非法信号返回-1
#include <stdio.h> #include <signal.h> int main(int argc,const char* argv[]) {sigset_t set;sigfillset(&set);sigemptyset(&set); sigaddset(&set,2);sigaddset(&set,7); for(int i=1; i<=128; i++) { printf("信号%d 状态:%d\n",i,sigismember(&set,i));} }
信号的递送与未决:
-
当信号产生后,系统内核会在其内部维护的进程表中,给响应信号的进程设置一个对应的标志位,着整个过程称为信号的递送
-
在信号产生到完成递送之间会存在一段时间间隔,处于这个时间间隔的信号状态是“未决”
信号屏蔽:
-
每个进程都有用一个信号掩码(signal mask,就是一个信号集),其中存在的信号是需要被该进程屏蔽的信号
-
让需要屏蔽的信号处于“未决状态”,当可以接收信号时,让其退出未决状态,完成递送
-
当执行一些特殊的且不想被干扰中断的操作时,例如:更新数据库敏感操作,此时可以把信号放入信号屏蔽集中,等操作完成后,再从信号屏蔽集中删除,继续处理信号,能保证敏感操作的安全性
// 信号屏蔽集的操作函数 int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); 功能:修改当前进程的信号掩码(屏蔽集) how:修改信号掩码的方式:SIG_BLOCK 将set中的信号加入到信号掩码中SIG_UNBLOCK 从信号掩码中把set中的信号删除SIG_SETMASK 把set中的信号替换掉信号掩码的所有信号 set:信号集 用于设置 oldsel:信号集 用于获取旧信号集 NULL则不获取
#include <stdio.h> #include <signal.h> #include <unistd.h> void sigint(int num) { printf("按下了Ctrl+C\n"); } void sigrtmin(int num) {printf("我可靠!\n"); } int main(int argc,const char* argv[]) {signal(SIGINT,sigint);signal(34,sigrtmin); sigset_t set,old_set;sigemptyset(&set); // 给信号集添加信号sigaddset(&set,SIGINT);sigaddset(&set,34);// 设置信号屏蔽sigprocmask(SIG_BLOCK,&set,&old_set);printf("我是进程%u\n",getpid());sleep(15);printf("我醒了,解除屏蔽!\n");// 还原屏蔽,解除屏蔽sigprocmask(SIG_SETMASK,&old_set,NULL);for(;;); }
对于可靠和不可靠信号屏蔽的区别:
-
对于不可靠信号,通过信号屏蔽该信号后,在信号屏蔽期间,该信号产生多次,都只会被屏蔽第一个,只有第一个处于未决,剩余的都不参与排队直接忽略,当解除屏蔽后,只会有第一个不可靠信号被完成递送
-
相反,对于所有在屏蔽期间产生的可靠信号,都会排队变成未决,当屏蔽接触后,会按照次序全部完成递送