信号的处理:
每一个信号实际都对应了某个事件,当进程收到了一个信号,那么就意味着现在有一个重要的事件要处理,因此会打断我们当前的操作,然后去处理这个事件。
信号还有一个名字:信号的递达。
那么进程什么时候会去检测pending集合,看有没有信号需要去处理?什么时候处理信号?
进程是在从**内核态切换到用户态**
的时候会去检测一下是否有信号需要去处理。
处理方式:
- 默认处理方式:操作系统原有定义好的,对于一个信号所对应事件的处理;
- 忽略处理方式:忽略和阻塞完全不同,一个被忽略信号来了之后就直接被丢弃了,忽略信号不会修改位图;而阻塞信号会修改位图,只是信号暂时不被处理。 3. 自定义处理方式:我们用户自己定义的一个信号处理方法,然后告诉操作系统,当这个信号来了之后,就按我定义的这个方法处理。
注:SIGSTOP和 SIGKILL无法被忽略,无法自定义处理
signal
#include <signal.h>
typedef void (*sighandler_t)(int);(函数指针,函数返回值为void)
sighandler_t signal(int signum, sighandler_t handler);
功能:用于修改一个信号的处理方式
signum: 用于指定修改哪个信号的处理
handler : 用于指定处理方式 (函数)
SIG_IGN :忽略处理
SIG_DFL:默认处理
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
int main()
{
//sighandler_t signal(int signum, sighandler_t handler);
signal(SIGINT,SIG_IGN); //将SIGINT信号设置为SIG_IGN(忽略处理),这时ctrl+c不会使进程停止
getchar();
signal(SIGINT,SIG_DFL);//将SIGINT信号设置为SIG_DFL(默认处理),这时ctrl+c使进程停止
while(1)
{
printf("happy\n");
sleep(1);
}
return 0;
}
如果是对信号忽略处理,信号会被丢弃,而不会注册。如下:即ctrl+c被忽略后,getchar( )即按回车后,恢复默认,程序会继续运行,如果再次按ctrl+c程序会退出:
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
int main()
{
sigset_t mask;
sigemptyset(&mask); //清空信号集
sigaddset(&mask,SIGINT);//将信号SIGINT放在
sigset_t oldmask;
sigemptyset(&oldmask); //清空信号集
sigprocmask(SIG_BLOCK,&mask,&oldmask); //将mask中信号进行阻塞
getchar();
sigprocmask(SIG_UNBLOCK,&mask,NULL); //将mask中信号解除阻塞
while(1)
{
printf("happy\n");
sleep(1);
}
return 0;
}
如果对信号阻塞处理,信号依然会注册在pending集合中。ctrl+c被阻塞,按crtl+c没反应,但getchar( )即回车后,取消阻塞后,进程会直接退出。
以上两个代码主要为了体现信号取消和阻塞的区别。
signal信号自定义处理:
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void sigcb(int signum)
{
printf("define by myself\n");
}
int main()
{
signal(SIGINT,sigcb); //用户自己定义信号处理方式
getchar();
signal(SIGINT,SIG_DFL); //信号处理方式恢复默认
while(1)
{
printf("happy\n");
sleep(1);
}
return 0;
}
sigaction:
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
功能:用于修改一个信号的处理方式
signum : 用于指定修改哪个信号的处理方式
act : 给指定信号要指定的处理方式
oldact :用于保存这个信号原来的处理方式
struct sigaction结构体介绍如下
struct sigaction {
void (*sa_handler)(int); //自定义处理方式
void (*sa_sigaction)(int, siginfo_t *, void *); //自定义处理方式,但是可以接收信号携带的参数
sigset_t sa_mask; //在处理信号的时候,希望这个处理过程不被其他信号到来打扰,因此sa_mask就是用于在处理信号时要阻塞的信号
int sa_flags;//选项标志,决定用哪一个成员函数作为信号处理的接口,如果是0就是sa_handler,如果是SA_SIGINFO就是sa_sigaction
void (*sa_restorer)(void);
};
//该程序功能:SIGINT信号处理方式自定义为打印 printf("define by myself\n");并且睡5秒,在这5秒期间,SIGQUIT信号被阻塞
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void sigcb(int signum)
{
printf("define by myself\n");
sleep(5);
}
int main()
{
//int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
struct sigaction act;
struct sigaction oldact;
sigemptyset(&act.sa_mask); //清空信号集,以防有影响
act.sa_flags=0; //sa_hanlder处理方式
act.sa_handler=sigcb;//处理方式为void (*sa_handler)(int signo)
sigaddset(&act.sa_mask,SIGQUIT);//在SIGINT信号处理期间,SIGQUIT信号阻塞
sigaction(SIGINT,&act,&oldact); //将SIGINT信号设置我自定义处理方式,并且将该信号原本处理方式保存于oldact中
while(1)
{
printf("happy\n");
sleep(1);
}
return 0;
}