Linux---信号及其使用简单讲解

在学习信号之前,我们先要知道,信号与信号量不是同一个东西。信号量主要是实现进程之间的同步与互斥,主要用于进程间通信。

在这里插入图片描述
这就是一个信号,现实生活中信号也特别常见。

信号的作用
我们先想一下在现实生活中信号主要是通知一件事情的,其实在操作系统中,信号也扮演着这样的角色。
在操作系统中,通知一个进程发生某一个事件,打断当前进程的操作,去处理这个事件。软件中断

查看信号
进程在相应信号之前必须先知道该信号是什么意思。
kill -l
在这里插入图片描述
上面共62中信号,其中没有32,33信号。
1-31号信号:信号有其对应的事件,非可靠信号。
34-64号信号:没有对应的事件,可靠信号。
可靠信号与不可靠信号最主要的区别就是可靠信号不会丢失事件,不可靠信号会丢失事件。

信号的生命周期

信号的产生
  • 硬件:ctrl+c

  • 软件:

    • 命令:kill -信号 pid
      kill命令杀死一个进程,主要是因为其想进程发送15号终止信号。

    • 函数:
      int kill(pid_t pid,int sig),向指定的进程发送指定的信号。
      int raise(int sig)给调用进程自身发送指定的信号。
      abort(void)向调用进程发送SIGABRT信号,使进程异常退出。
      unsigned int alarm(unsigned int seconds)second秒后调用进程发送SIGALRM信号,告诉进程时间到退出。

信号在进程中的注册

让进程知道自己收到了一个信号,进程就是一个pcb,Linux下在pcb结构体中定义了一个信号的集合set(位图),若给进程发送一个信号,则将这个信号对应的位置的二进制位置1。
位图只能标记进程是否收到这个信号,无法确定信号收到多少次,所以在内核中其实还有一个链表。
sigset_t set;申请一个set集合
sigemptyset(&set);清空一个set集合,因为set集合为栈上申请的空间,所以会存在数据
int sigfillset(sigset_t *set); 将所有信号添加到set中
int sigaddset(sigset_t *set,int signum); 将信号值为signum添加到set中

  • 非可靠信号的注册:在注册信号时,判断当前信号是否已经注册过(位图是否为1),若没有注册,则添加结点,修改位图,反之,如果已经注册过则什么也不干。这就导致在链表中只有一个结点,后到来的信号就被丢弃。

  • 可靠信号的注册:在注册时,每次针对新到来的信号都会创一个新的结点添加到链表中,并且二进制置1,链表中有多个相同的结点。

信号在进程中的注销
  • 非可靠信号:删除结点,位图置0,因为非可靠信号最多只有一个结点。
  • 可靠信号:删除结点,若还有相同结点,位图不变,若没有相同结点则位图置0,表示没有该信号。
信号的处理

进程在收到信号之后,针对这个信号的事件找到它对应的处理函数。

  • 默认处理:系统已经默认好的处理方式。
  • 忽略处理:处理动作什么都不做。
  • 自定义处理:用户自定义信号处理函数,使用这个信号处理函数替换原本信号处理函数。

信号处理方式的修改

  • sighandler_t signal(int signum,sighandle_t handler);修改一个信号的处理动作的回调函数。
    signum:信号值。
    handler:函数指针。 sighandler_t 函数指针类型 —> typedef void(*sighandler_t)(int signo),signo:当信号到来时,系统向回调函数传入的信号值。

自定义信号的捕捉流程
信号的处理:当前进程从用户态切换到内核态之前进行处理。
程序从用户态切换到内核态的方法:中断,异常,系统调用。

信号的阻塞
在进程中标记,哪个信号注册之后,暂时不去处理,知道信号接触阻塞。

阻塞一个信号被抵达,进程pcb中有一个信号block集合,用户可以在这个集合中标记哪些信号被阻塞。

本质: 将信号添加到block集合中,则表示这个信号被阻塞,当信号传递过来时,暂时不处理。
int sigprocmask(int how,const sigset_t *set,sigset_t *oldset
how:即将要对pcb中block集合所作的操作,有三个选项:

  • SIG_BLOCK:将第二个参数set集合中的信号,添加到block集合中。
  • SIG_UNBLOCK:将第二个参数set集合中的信号,从block集合中移除,解除阻塞
  • SIG_SETMASK:使用set集合替换block集合 block=set
    oldset:每当block集合发生改变时,都会将原本的block拷贝一份放到oldset集合中,方便后期还原block

注意:
1:信号阻塞时依旧能够进行信号注册,但是暂时不处理。
2:可靠信号注册多次,因此会阻塞处理多次,不可靠信号只能被注册一次,只阻塞处理一次。
3:9号信号与19号信号不能被阻塞。

#include<unistd.h>
#include<signal.h>
#include<stdlib.h>


void sigcb(int signo)
{
        printf("收到一个信号%d\n",signo);
}

int main()
{
		//修改信号的处理方式
        signal(SIGINT,sigcb); 
        signal(SIGRTMIN+5,sigcb);

        sigset_t set;//定义一个局部变量,有可能有数据留存,因此需要对其进行初始化
        sigemptyset(&set); //清空信号集合

        //int sigfillset(sigset_t *set);将所有信号添加到set中
        //int sigaddset(sigset_t *set,int signum);将signum添加到set中

        sigfillset(&set);
        sigprocmask(SIG_BLOCK,&set,NULL);//对set集合中的信号进行阻塞

        printf("回车继续\n");
        getchar();//等待标准输入换行,流程继续
        sigprocmask(SIG_UNBLOCK,&set,NULL);

        return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值