栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

【Linux】进程信号篇

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Linux】进程信号篇

文章目录

信号的概念与种类信号的产生

硬件产生方式软件产生方式扩展--根据信号值判断代码出错原因 信号的处理方式信号的注册信号的注销信号的自定义处理方式信号的阻塞信号的捕捉流程扩展

信号的概念与种类
    概念
    信号是一个软中断,这里有一个形象的例子来说明一下它的含义:

    所以说:信号只是告诉我们有这样一个信号,但是具体这个信号如何处理,什么时候处理是由进程决定的,所以是软中断种类
    我们可以通过kill -l 命令来查看所有的信号

    注意:总共有62个信号!没有32和33号信号
    其中
    1–31号信号被称为非实时信号,也叫非可靠信号,它在使用的过程中信号可能会丢失
    34–64号信号被称为实时信号,也叫可靠信号,它在使用的过程中信号不会丢失
信号的产生 硬件产生方式

    Ctrl + c
    产生的是2号信号SIGINT
    是一个中断信号

    Ctrl + z
    产生的是20号信号SIGTSTP
    是一个暂停信号

    Ctrl +
    产生的是3号信号SIGQUIT
    是一个退出信号

    kill命令向进程发送信号
    通过 kill -[信号值] [pid]向进程发送信号

软件产生方式
    kill函数
 #include 
 int kill (pid_t pid,int sig)

    raise函数
 int raise(int sig);


其实raise函数内部调用的依旧是kill函数

int raise(int sig)
{
	return kill(get(pid),sig);
}

代码测试

结果:与预期一致

扩展–根据信号值判断代码出错原因

回想之前在学习gdb调试的时候,有一种情况就是对崩溃后产生的coredump文件进行调试,进而确定程序崩溃的原因
现在我们可以通过对崩溃程序产生的coredump文件进行调试,通过信号值判断程序崩溃原因。
产生coredump文件的方式以及限制因素:

    解引用空指针、野指针(垂悬指针)

    除0

    越界访问


    这样都不崩溃?
    原因:
    操作系统容忍进程访问不属于自己的内存,但是有个前提条件,越界访问的内存,没有分配给其他进程所使用
    既然这样,我们来个更过分的:

    终于验证到了,现在调试一下产生的coredump文件

    double free


    gdb调试产生的coredump文件
信号的处理方式

    通过 man 7 signal 查看OS对信号的处理方式

    默认处理方式
    SIG_DFL
    在操作系统当中已经定义好信号的处理方式

    忽略处理方式
    SIG_ING 忽略处理
    联想到僵尸进程的产生原因:
    现在给出详细解释:

    子进程先于父进程退出, 子进程在退出的时候会给父进程发送SIGCHLD信号,而父进程接收到这个信号后,是忽略处理的,从而导致了父进程没有回收子进程的退出状态信息,因此子进程就变成了僵尸进程!

    自定义处理方式
    程序员可以更改信号的处理方式,定义一个函数,当进程收到该信号的时候,调用程序员自己写的函数。

信号的注册

    概念
    一个进程收到一个信号,这个过程称之为注册
    信号的注册和信号的注销是两个独立的过程

    内核中信号注册位图以及sigqueue队列的理解
    2.1 task_struct结构体内部有一个结构体变量 struct sigpending pending ,struct sigpending结构体有两个成员变量,一个是 struct list_head list(双向链表),另一个是 sigset_t signal(数组)
    2.2 我们具体研究这个 sigset_t signal 数组:
    sigset_t本质上是一个结构体,它的内部成员变量是一个数组:unsigned long sig[_NSIG_WORDS]
    对于这个数组,操作系统并没有将它当做数组来使用,而是把它看做是位图
    2.3 在Linux的64位平台下,long 以及 unsigned long占8个字节,也就是64个bit位,而目前信号的数量只有62个,所以每个bit位表示一个信号是足够的

上面说了这么多,理解起来可能会有一点绕,下面我就通过图示的方式解释一下:

在理清楚他们之间的关系后,现在开始整整意义上的理解这个数组是如何被当做位图来使用的。

可能有人又有疑问了:
既然数组的一个元素就可以搞定,为何又大费周章,给一个数组呢?
原因是为了后续可能会扩展的信号提供空间

    注册
    位图更改为1,添加sigqueue节点到sigqueue队列
    信号在注册的时候,会将信号对应的bit位由0改为1,表示当前进程收到了该信号
    在sigqueue队列中添加一个sigqueue节点。队列在OS内核当中本质上就是一个双向链表(具有先进先出的特性)
信号的注销

主要分为可靠信号和费可靠信号

信号的自定义处理方式

含义:让程序员自己定义某一个信号的处理方式,当进程收到该信号后就会执行程序员自定义的处理方式

    signal函数+测试代码
sighandler_t signal(int signum,sighandler_t handler);


9号信号(强杀)是不能被程序员自定义处理的函数
测试代码:


2. sigaction函数+测试代码

int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact)


后两个参数都是一个结构体指针,这里展开说明,该结构体的定义如下图:

下面对这五个成员变量进行说明:

测试代码:
情景一:自定义信号处理方式执行后手动结束进程


情景二:进程收到2号信号后先去执行自定义处理方式的函数,然后在该函数内部,再将2号信号的处理方式恢复为原来的方式

结合内核代码进行理解
信号的阻塞

理解要点
信号注册是注册,信号阻塞是阻塞**。信号的阻塞并不会影响信号的注册**
进程收到这个信号之后,由于阻塞,暂时不处理该信号。内核代码理解

struct task_struct
{
    ........
    sigset_t blocked;
    .........
}

sigset_t blocked是一个位图,当要阻塞一个信号的时候,将该信号对应的比特位设置为1即可

接口

int sigprocmask(int how,const sigset_t* set,sigset_t* oldset)

代码验证
验证方式:阻塞“全部”信号,进程不退出,查看进行收到每一个信号(通过test函数实现)时的状态。



通过kill -9 将进程杀死

也可以通过kill - 19来停止这个进程

结论:9号和19号信号不能被阻塞

信号的捕捉流程
    信号的处理时机
    从内核态切换到用户态的时候,会调用do_signal函数处理信号,该函数会判断是否有信号并做出相应的操作:
    处理信号的时候,不同的处理方式
    画图理解这个过程
    常见的进入内核的方式
    调用系统调用函数
    内存访问越界,访问空指针
    调用库函数
扩展
    父子进程 + 进程等待 + 自定义信号处理方式
    我们前面学习的进程等待,父进程在等待子进程退出,回收它的退出状态信息的时候,有两种方式,分别是:
    wait接口,阻塞等待
    waitpid接口,非阻塞等待,搭配循环使用
    这两种方式父进程在等待子进程期间都是无法执行其他活动的
    由于父进程无法执行其他代码,导致父进程的效率低下,我们可以使用信号的方式来解决这个问题.具体思路如下:

我们都知道,父进程回收子进程退出信息接收到的是SIGCHLD信号,因此我们可以将该信号的处理方式自定义一下,然后在接收到该信号的时候,再转去执行自定义处理方式里面的wait函数来回收子进程的退出状态信息。
通过上面的方式,我们就会“解放”父进程,让他在等待子进程退出的同时能够去执行其他代码!

    volatile关键字

    结合自定义信号处理函数进行代码验证:
    情景一:不使用volatile关键字。构造一个循环场景,通过信号执行自定义的信号处理函数改变相应的循环判断条件,观察现象


现在来一个小改动

其余不改变,我们再次观察现象:

情景二:使用volatile关键字。构造一个循环场景,通过信号执行自定义的信号处理函数改变相应的循环判断条件,观察现象


正常退出,原因是加了volatile关键字,因此每次都会从内存读取数据,说以值改变编译器每次都会读取到新的数据。

以上就是对进程信号相关内容的梳理!各位看官,感觉有所帮助,还请一键三连~~

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/778918.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号