什么是信号集:
-
是一种专门用于存储多个信号的数据类型sigset_t
-
该类型占128字节,每个字节代表了一种信号的有或无
int sigemptyset(sigset_t *set);
功能:将信号集set中的所有信号置0 清空信号集
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:信号集 用于设置
oldset:信号集 用于获取旧信号集 NULL则不获取
#include <stdio.h>
#include <signal.h>
#include <stdlib.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,oldset;
sigemptyset(&set);
// 给信号集添加信号
sigaddset(&set,SIGINT);
sigaddset(&set,34);
// 设置信号屏蔽
sigprocmask(SIG_BLOCK,&set,&oldset);
printf("我是进程%u\n",getpid());
sleep(15);
printf("我醒了,解除屏蔽\n");
// 屏蔽解除
sigprocmask(SIG_SETMASK,&oldset,NULL);
for(;;);
}
对于可靠和不可靠信号屏蔽的信号:
-
对于不可靠信号,通过信号屏蔽该信号后,在信号屏蔽期间,该信号产生多次,都只会被屏蔽第一个,只有第一个处于未决,剩余的都不参与排队直接忽略,当解除屏蔽后,只会有第一个不可靠信号被完成递送
-
相反,对于所有在屏蔽期间产生的可靠信号,都会排队变成未决,当屏蔽解除后,会按照次序全部完成递送
带参的信号发送与捕获
-
可以让不同进程之间发送信号时,带上一些简易的数据,完成不同进程之间简单通信,这叫带参数的信号发送
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
功能:能够设置带参数的信号处理函数方案
计时器
系统为每个进程维护三个计时器:
-
真实计时器:进程运行的实际时间
-
虚拟计时器:进程运行在用户态所消耗的时间
-
实用计时器:是进程在用户态和内核态消耗的时间之和
实际真正的时间(真实计时器) =用户态时间+内核时间+睡眠时间+状态切换耗时
通过设置计时器的起始时间和重复间隔时间给进程设置定时事件,例如定时保存、定时上传操作。
获取\设置定时器
#include <sys/time.h>
int getitimer(int which, struct itimerval *curr_value);
功能:获取当前进程的某个定时器的定时方案
int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value);
功能:设置当前进程的定时方案
which:指定哪个计时器
ITIMER_REAL 真实计时器 SIGALRM(14)
ITIMER_VIRTUAL 虚拟计时器 SIGVTALRM(26)
ITIMER_PROF 实用计时器
struct itimerval {
struct timeval it_interval; // 间隔时间,定时器开始后,每间隔这个时间就会再发出一次定时器信号,一直重复
struct timeval it_value; // 开始时间,从该时间开始发送第一个定时器信号
}
struct timeval {
time_t tv_sec; // 秒数
suseconds_t tv_usec; // 微秒,不能超过10^6
}