Linux 进程信号

Linux 进程信号

信号的概念

程序在正常执行过程中出现的异常情况, Linux可以响应这些异常的情况,当这些异常情况发生时,我们的程序就要做出相应的动作

产生信号的来源

用户按键
非法的内存访问
硬件故障
浮点数溢出
软件条件产生

处理信号的方式

缺省处理
忽略(SIGKILL SIGSTOP 不能忽略)
捕捉信号(SLGKILL SIGSTOP 不能被捕获处理)

常见的信号


13号信号 SIGPIPE 管道破裂信号
18号信号 SIGCONT 继续执行信号
29号信号 SIGIO 异步IO信号

注册信号

函数原型:

void (*signal(int signum, void (*handler)(int)))(int);
void (*signal(int signum, //要进行处理的信号
     void (*handler)(int)) //信号处理函数
                           //SIG_IGN 忽略
                           //SIG_DEF 缺省处理动作
                           //SIG_ERR 
     )(int);

例子:先让Ctrl+C不执行中断功能,当按Ctrl+\后让Ctrl+C恢复原功能

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

void handler1(int s)
{
    printf("收到%d号信号,但是我不死\n", s);
}

void (*handler_t)(int) = NULL;


void handler_quit(int s)
{
    printf("收到%d号信号\n", s);
    signal(SIGINT, handler_t);
}


int main()
{
    handler_t = signal(SIGINT, handler1);
    signal(SIGQUIT, handler_quit);
    for(; ;)
    {
        printf(".");
        sleep(1);
        fflush(stdout);
    }
    return 0;
}

信号的分类

不可靠信号(1~31):
1. 会出现丢失
2. 执行完信号处理函数之后,会恢复到缺省动作(Linux解决)

可靠信号(34~64):
1. 不会出现信号丢失
2. 不会出现恢复到缺省动作

非实时信号:不可靠信号都是非实时信号,在信号递达之前产生多次只计一次

实时信号:可靠信号都是实时信号,在递达之前产生多次可以依次放在一个队列里

操作系统发送信号的原理

对于不可靠信号,在进程的PCB中有一个32bit的位图,位图的每一位代表了一个相应编号的信号。操作系统在向某个发送信号时,首先找到该进程的PCB,然后将PCB中位图的相应位置值1。信号对于进程的控制流来说是异步的。

信号在内核中的示意图

产生信号的方法

  1. 键盘组合按键
  2. bash中的kill命令
  3. 系统调用 kill函数 、raise函数、abort函数
  4. 由软件条件产生信号 alarm函数

alarm函数:

#include<unistd.h>
unsigned int alarm(unsigend int seconds);

当seconds秒后向当前进程发送闹钟信号SIGALARM。

阻塞信号

信号递达 delvery:实际执行信号的处理动作
信号未决 pending:信号从产生到递达的中间状态
信号阻塞 block:被阻塞的信号将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达动作。

三张表:
block(位图) 为1表示信号被屏蔽,不会被抵达
pending(位图) 为1表示产生该信号
handler(函数指针数组) 对应位置表示对信号的处理方法
三张表
如上图所示,在task_struct结构体(PCB)中有两张位图表和一个函数指针数组,每个位图的低32位中的每一位都代表一种信号;相应的,函数指针数组中的每一个函数指针都对应着一种信号。在图示中,1号信号SIGHUP没有产生也没有被阻塞,该信号响应默认的处理动作;2号信号SIGINT产生了但是被阻塞了,该信号响应的处理动作为忽略;3号信号SIGOUT产生了,没有被阻塞,该信号响应的处理动作为用户自定义的处理动作。

进程什么时候处理信号?

当进程从内核态切换为用户态时检查是否有信号(查看pending表)

信号捕捉过程

如果信号的处理函数为自定义的,在信号递达时就会调用这个函数,这称为捕捉信号。

信号捕捉过程
如上图所示,用户态的进程在运行过程中遇到异常(收到信号),进入内核态保存上下文,由于定义了信号捕捉函数,此时再转去用户态执行自定义的函数,自定义函数执行完后,返回到内核态去,再调用内核中的函数来返回到原来的位置。

函数重入

函数被不同的控制流程调用,发生在一个调用还没返回时就再次进入该函数的现象。

可重入的条件:
函数只访问自己的局部变量或参数

符合下列条件之一就是不可重入:
1. 调用了malloc或free,因为它们是用全局链表来管理的,有可能因为重入造成错乱。
2. 调用了标准I/O库。因为标准I/O库的很多实现都是以不可重入的方式在使用全局数据结构。

竞态条件

程序在运行过程中由于时序问题而导致的错误,称为竞态条件

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值