信号的处理

信号的处理:

每一个信号实际都对应了某个事件,当进程收到了一个信号,那么就意味着现在有一个重要的事件要处理,因此会打断我们当前的操作,然后去处理这个事件。
信号还有一个名字:信号的递达。
那么进程什么时候会去检测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;
}

这里写图片描述

猜你喜欢

转载自blog.csdn.net/sophia__yu/article/details/82320121