操作系统中,信号的产生可以告诉系统要去执行某个操作。操作系统中有默认的信号处理函数。我们也可以更改默认的信号处理函数,由我们自己写。——信号捕捉
我们先来看看信号在内核中是怎样的:
信号对于操作系统来说,分为3类:
1.阻塞信号
2.未决信号
3.忽略
每个信号都有两个标志位分别为阻塞(block)和未决(pending),还有一个函数指针表示处理动作。
信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清楚该标志。
ps:Linux中,常规信号在递达之前产生多次只计一次。
我们看看信号集操作函数:
#include<signal.h>
//初始化set所指向的信号集,使其中所有信号集的对应bit清零
int sigemptyset(sigset_t *set);
//初始化set指向的信号集,该信号集表示系统支持的所有信号
int sigfillset(siget_t *set);
//添加某种信号
int sigaddset(siget_t *set,int signo);
//删除某种信号
int sigdelset(siget_t *set,int signo);
//判断set信号集有效信号中是否包含某种信号,返回值(bool类型)
int sigismember(const siget_t *set,int signo);
//读取或更改进程的信号屏蔽字(阻塞信号集)
int sigprocmask(int how,const sigset_t *set,sigget_t *oset)
//读取当前进程的未决信号集,set,输出型参数
sigpending(sigset_t *set);
函数使用例子:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
void printfsigset(sigset_t *set)
{
int i = 0;
for(i=0;i<32;i++)
{
if(sigismember(set,i)) //判断信号是否在未决信号集中
{
putchar('1');
}
else{
putchar('0');
}
}
puts("");
}
int main()
{
sigset_t s,p; //信号集
sigemptyset(&s); //初始化阻塞信号集
sigaddset(&s,SIGINT); //添加信号
sigprocmask(SIG_BLOCK,&s,NULL); //设置到信号集中
while(1)
{
sigpending(&p); //获取未决信号集
printfsigset(&p);
sleep(1);
}
return 0;
}
运行结果:
当我们 Ctrl + C 时,发送SIGINT 2号信号。但是我们设置为阻塞,未进行处理,所以在未决信号集中标着1,并没有递达。
我们按 Ctrl + \ 时,发送SIGQUIT,由于该信号并未阻塞,所以程序结束,段错误。
由于操作系统中对信号有默认的处理函数,我们希望产生某个信号的时候,处理函数由我们自己定义。
函数:
#include<signal.h>
int sigaction(int signo,const struct sigaction *act,struct sigaction *oact);
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
act 和 oact指向的是sigaction结构体,signo是指定信号的编号。
将sa_handler赋值为常数SIGIGN传给sigaction表示忽略信号,
赋值为SIG_DFL表示指向系统默认函数,
赋值为一个函数指针表示用自定义函数捕捉信号,或者说向内核注册了一个信号处理函数。
简单例子:
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void sig_alrm(int signo)
{
//do nothing
/*
int i = 0;
for(i = 1; i < 6;i++)
{
printf("%d\n",i);
sleep(1);
fflush(stdout);
}
*/
}
unsigned int mysleep(unsigned int nsecs)
{
struct sigaction new,old;
unsigned int unslept = 0;
new.sa_handler = sig_alrm; //自己定义的信号处理函数
sigemptyset(&new.sa_mask); //初始化信号集
new.sa_flags = 0;
sigaction(SIGALRM,&new,&old); //SIGALRM 使用自己的定义函数
alarm(nsecs); //定时器
pause();
unslept = alarm(0); //清空定时器
sigaction(SIGALRM,&old,NULL); //恢复成默认的信函处理函数
return unslept;
}
int main()
{
while(1)
{
mysleep(5);
printf("5 seconds passed\n");
}
return 0;
}
自己定义的sig_alrm() do nothing :
sig_alrm() to do: