Linux----详解信号

本文详细探讨了Linux系统中的信号,包括信号的概念、产生条件、处理方式和常见系统函数。信号是进程间通信的异步机制,有多种产生方式,如终端按键、硬件异常和系统函数。信号的处理包括默认动作、忽略和自定义处理函数。文章通过实例演示了如何捕获和处理信号,如SIGINT、SIGSEGV和SIGALRM,并介绍了阻塞信号、信号集操作以及信号的三种状态。
摘要由CSDN通过智能技术生成

信号的概念

信号是进程间通信机制中唯一的异步机制
来看看在Linux中都有哪些信号
kill -l 命令可以查看Linux中的信号列表
这里写图片描述
我们可以看到每个信号都有一个编号和一个宏定义名称,这些宏定义可以在头文件signal.h中找到。而且可以发现的是没有32、33号信号。1-31号信号叫做普通信号,34-64号信号叫做实时信号
在这里对这些信号就不做详细的解释了,可以查看man手册 man 7 signal
这里写图片描述


信号的产生

先从我们的生活中说起,我们生活中也有很多信号,“铃声”、“红绿灯”,Linux中的信号也是一样的,是为了提供一个机制在需要的时候告诉某个进程该怎样做。是一种规定,便于系统操作。
信号的发送者有很多,比如终端驱动程序,进程,系统等。而接收者大多是一个进程。
那怎样就算是给某进程发信号呢?事实上,给进程发信号就是修改目标进程PCB结构体中的关于信号的字段。由于进程是否接收到信号本身是一个原子问题。它要么收到,要么没收到。所以PCB中就用位图来表示进程是否收到信号,只需要修改一个比特位(操作系统完成):收到信号就置1,没收到就为0

信号产生条件:
  • 通过终端按键产生信号
  • 硬件异常产生的信号
  • 调用系统函数向进程发送信号
  • 由软件条件产生信号

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
在解释信号产生条件之前,我们先来谈谈遇到信号我们该如何处理呢?
我们一共有三种解决方式:

  • 执行该信号的默认处理动作
  • 忽略该信号
  • 执行自定义动作

对于大部分的信号来说,默认处理动作,都是终止进程,当然还有继续、暂停等;
忽略该信号就是继续执行自己的操作,但需要注意的是有两个特殊信号SIGKILL信号和 SIGSTOP信号,这两个信号是不能被忽略的;
自定义动作,就是捕捉该信号,用户本身提供一个信号处理函数,内核在处理这个信号时,切换到用户态去执行这个函数,这就是捕捉一个信号。
来看看信号捕捉函数的原型:

 #include <signal.h>

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);
//signum:需要捕捉的信号
//handler:该信号需要进行的动作

我们可以发现,sighandler_t是一个函数指针,函数类型是void*,参数是int。接下来在说明信号产生时,我们再来做验证

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
接下来解释一下这四种情况:


1.通过终端按键产生信号

当我们想让一个正在运行的程序终止时,我们经常会按下组合键 Ctrl+CCtrl+\ ,实际上Ctrl+C是给该进程发送了SIGINT信号,而Ctrl+\是给该进程发送SIGQUIT
SIGINT的默认处理动作是终止进程,SIGQUIT的默认处理动作是终止进程并且Core Dump
我们来验证一下这两个信号:
写个死循环,分别利用Ctrl+C和Ctrl+\终止程序

#include <stdio.h>
#include <stdlib.h>

int main()
{
    while(1)
    {
        printf("hello signal\n");
        sleep(1);
    }
    return 0;
}

Ctrl+C
这里写图片描述
Ctrl+\ ,我们把代码修改一下,捕捉SIGINT信号,然后再利用Ctrl+\来终止

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>

void handler(int signo)
{
    printf("%d ,you can't kill me...\n",signo);
}

int main()
{
    signal(SIGINT,handler);
    while(1)
    {
        printf("hello signal\n");
        sleep(1);
    }
    return 0;
}

这里写图片描述
由结果可以发现,我们按下的Ctrl+C确实是2号信号SIGINT,利用同样的方法也可以验证Ctrl+\


2. 硬件异常产生的信号

由硬件异常产生的信号是由硬件检测到并通知内核,然后内核向当前进程发送适当的信号。例如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为发送了SIGSEGV信号(11号信号)给进程,再例如当前进程出现了除零错误,CPU的运算单元会产生异常,内核将这个异常解释为发送了SIGFPE信号(8号信号)给进程。
来验证一下:在刚刚的代码中加入产生异常的代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>

void handler(int signo)
{
    printf("recv %d signal.\n",signo);
    exit(1);
}

int main()
{
    signal(SIGSEGV,handler);
    while(1)
    {
        printf("hello signal\n");
        sleep(1);
        int *p=(int*)10;
        *p=20;//访问非法内存
    }
    return
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值