【Linux】信号的产生、注册、注销、处理、阻塞

首先,我们要明确一个概念,信号和信号量不是同一个东西!
在上一篇博客中有提到,信号量本质上就是一个计数器,用于实现进程间的同步与互斥,而信号则是一个软件中断,是去通知进程发生了某个事件,打断进程当前的操作去处理这个事件。
在Linux中,我们可以使用 kill -l去查看所有信号,其中1 ~ 31号信号是非可靠信号,有可能会产生信号丢失情况,34 ~ 64号信号是可靠信号,不会产生信号丢失情况。

  • 信号的产生:
    信号的产生分为软件和硬件两个方面:
    硬件:
    ctrl + c 产生中断SIGINT信号
    ctrl + z 产生停止信号(进入停止态而不是退出)
    ctrl + \ 产生退出信号
    软件:
    int kill(pid_t pid,int sig); 向指定进程发送指定信号
    int raise(int signum); 给进程自身发送指定的信号
    void abort(); 给进程自身发送SIGABRT异常信号
    int alarm(int sec); 定时器,sec秒后给进程自身发送SIGALRM信号

  • 信号在进程中注册:
    在进程的PCB中有一个表(位图)存放未决信号集合。进程运行中通过这张表的数据能够获知自己收到了哪个信号。信号在进程中注册就是修改这个位图,将对应的信号位置为1,但位图只能表示有没有收到信号,无法表示收到了多少个信号。在PCB中还有一个sigqueue双向链表,链表中有多少个相同信号信息节点,就代表这个信号注册了多少次。
    可靠信号的注册:不管信号是否已经被注册过,都会注册一次,添加一个信号节点。
    非可靠信号的注册:如果信号已经被注册并且还未被处理,则什么都不做,否则将注册。

  • 信号的注销:
    信号的注销就是消除信号在PCB中的痕迹,删除一个信号的sigqueue节点,没有相同节点则位图置0。

  • 信号的处理:
    处理一个事件,就是完成一个功能,在c语言中,一个功能的最小模块就是一个函数,那么信号的处理就是调用信号的处理函数,执行这一个函数。
    信号的处理分为三种方式,并且信号的处理方式是可修改的:
    默认处理方式:系统中已经定义好的,没有特殊指定时采用的处理方式;
    忽略处理方式:对于这个信号的处理方式就是不处理,什么都不做;
    自定义处理方式:程序员自己去定义一个信号处理函数作为指定事件的处理函数。
    修改信号的处理方式:
    typedef void( * sighandler_t)(int);
    sighandler_t signal(int signum,sighandler_t handler);
    sighandler_t是函数指针类型名称
    signum是信号值,指定要修改哪个信号的处理方式的信号值
    handler是函数指针,用于指定signum信号新的信号处理函数,SIG_IGN表示忽略处理方式,SIG_DFL表示默认处理方式。

  • 信号的阻塞:
    进程收到信号后,暂时不去处理,等到解除阻塞后再去处理。在PCB中,也有一个阻塞信号集合的位图,被添加到这个位图中的信号就表示要阻塞。
    int sigprocmask(int how,const sigset_t * set,sigset_t * oldset);
    how表示要对阻塞集合进行的操作:
    SIG_BLOCK:将set集合中的信号添加到阻塞集合
    SIG_UNBLOCK:将set集合中的信号从阻塞集合移除
    SIG_SETMASK:直接将阻塞集合修改为set
    sigset_t 表示一个信号位图的结构体
    oldset表示用于保留修改前原有阻塞集合中的信号,便于还原,可以置为NULL。
    注意:SIGSTOP和SIGKILL信号无法被阻塞,无法被自定义,无法被忽略。

猜你喜欢

转载自blog.csdn.net/weixin_45177279/article/details/114954555
今日推荐