IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 【Linux】进程信号 -> 正文阅读

[系统运维]【Linux】进程信号

目录

信号的概念

种类

信号的产生

硬件产生方式

软件产生方式?

根据信号值判断代码出错的原因

信号的处理方式?

信号的注册

概念:

内核中信号注册位图以及sigqueue队列的理解:

注册

信号的注销?

信号的自定义处理方式?

信号阻塞?

信号的捕捉流程

其他扩展内容:


信号的概念

信号只是告诉我们有这样一个信号,但是具体这个信号如何处理,什么时候处理是由进程决定的,所以是软中断。

种类

可以通过kill -l命令来查看所有信号。

注意:总共有62个信号,没有32和33号信号。

其中1-31号信号被称之为非实时信号,也叫非可靠信号,它在使用的过程中信号可能会丢失。34-64号信号被称为实时信号,也叫可靠信号,它在使用过程中信号不会丢失。

信号的产生

硬件产生方式

1、Ctrl + c

产生的是2号信号SIGINT,是一个中断信号。

2、Ctrl + z

产生的是20号信号SIGTSTP,是一个暂停信号。

3、Ctrl + \

产生的是3号信号SIGQUIT,是一个暂停信号。

4、kill命令向进程发送信号

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

软件产生方式?

1、kill函数

pid:进程号,给哪个进程发信号,就填写哪个进程的进程号。

sig:要发送的信号值。?

??

2、raise函数

?谁调用给谁发信号,该函数在实现过程中是调用kill函数的。

sig:要发送的信号值

根据信号值判断代码出错的原因

在之前gdb调试的时候,有一种情况就是对崩溃后产生的coredump文件进行调试,进而确定程序崩溃原因。产生coredump文件的方式以及限制因素:

前提:能够生成coredump文件,ulimit -a查看corefilesize的大小。

如果是0:通过ulimit -c unlimited命令将其改为无限制。

unlimited权限只是说在操作系统层面,不会限制你产生coredump文件。但是注意:硬盘空间大小也是决定能否产生coredump文件的一个因素,coredump文件大小必须小于磁盘空间大小才能产生。?

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

?2、除0

3、越界访问

4、double free

信号的处理方式?

1、通过man 7 signal查看操作系统对信号的处理方式。

2、默认处理方式?

SIG_DFL

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

?3、忽略处理方式

SIG_ING

联想到僵尸进程的产生原因:

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

?4、自定义处理方式

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

信号的注册

概念:

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

内核中信号注册位图以及sigqueue队列的理解:

task_struct 结构体内部有一个结构体变量struct sigpending pending,struct sigpending结构体有两个成员变量,一个是 struct list_head? list(双向链表),另一个是sigset_t signal (数组)

具体研究以下这个数组,sigset_t本质上是一个结构体,它的内部成员变量是一个数组:unsignal long sig[_NSIG_WORDS],对于这个数组,操作系统并没有将它当作数组使用,而是把它看作是位图;在Linux64位平台下,long占8个字节,也就是64个bit位,而目前信号的数量只有62个,所以每个bit位表示一个信号是足够的。?

该数组中的每一个元素有64个比特位,对于现有的62个信号,规定每一个信号对应数组中某个比特位,其中比特位位1表示接收到了信号,0表示没有接受到该信号。

如图:

?既然数组的一个元素就可以搞定,为何又大费周章,给一个数组呢?

原因是为了后续可能会扩展的信号提供空间。

注册

位图更改为1,添加sigqueue节点到sigqueue队列。

信号在注册的时候,会将信号对应的bit位由0改为1,表示当前进程收到了该信号。

在sigqueue队列中添加一个sigqueue节点。队列在操作系统当中本质上是一个双向链表(具有先进先出的特点)

非实时信号注册:

第一次注册:修改sig位图(0-->1);修改sigqueue队列

第二次注册:修改sig位图(1-->1);不会添加sigqueue节点

?实时信号注册:

第一次注册:修改sig位图,修改sigqueue队列

第二次注册:修改sig位图,添加sigqueue节点到sigqueue队列

信号的注销?

非可靠信号:

1、将信号对应的sig位图当中的bit位置为0

2、将对应信号的sigqueue节点进行出队操作

可靠信号 :

1、将对应信号的sigqueue节点进行出队操作

2、判断sigqueue队列当中是否还有相同信号的sigueue节点;如果有,比特位不作修改;没有,对应比特位置为0?

信号的自定义处理方式?

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

1、signal函数?

signum :信号值

handler:等改为哪一个处理函数,是一个函数指针,接受一个函数地址

handler指向的函数是一个回调函数,再调用 signal函数的时候,给第二个参数传递函数地址的时候并没有调用传递的函数,而是在等进程收到了某个信号之后,才会调刚才注册的函数。?

注意:9号信号是不能被程序员自定义处理的。

?

2、sigaction

signum:信号量

act:将信号的处理方式改为act指针指向的内容

oldact:原来信号的处理方式,输出型参数,用户只需要提供空间,后续可以通过oldact查看该信号原来的操作。?

后两个参数都是一个结构体指针:

void (*sa_handler)(int):保存信号默认处理方式的函数指针

void (*sa_sigaction)(int, siginfo_t*, void*):也是一个保存信号的处理方式的函数指针,但是? 没有使用;使用的时候需要配合sa_flags一起使用;当sa_flags的值为SA_SIGINFC的时候,信号按照sa_sigaction保存的函数地址进行处理。

sigset_t? sa_mask:?是一个sig位图,用来暂存进行在执行该信号的处理过程中收到的其他信号,后续会放到进程的信号的位图当中。

int sa_flags:我们一般情况下只会使用1和3

void? (*sa_restorer)(void):保留字段?

?结合内核理解:

信号阻塞?

信号的注册是信号的注册,信号阻塞时阻塞。信号的阻塞并不会影响信号的注册。进程收到这个信号之后,由于阻塞,暂时不处理该信号。

内核代码:

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

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

接口:

how:想让sigprocmask做什么

? ? ? ? SIG_BLOCK:设置某个给信号为阻塞状态

? ? ? ? SIG_UNBLOCK:设置某个信号为非阻塞状态

? ? ? ? SIG_SETMASK:用第二个参数set来替换原来的阻塞位图

set:新设置的阻塞位图

oldset:原来老的阻塞位图?

函数原理解析:当how为SIG_BLOCK时,函数会根据set,计算新的阻塞位图,计算方式是:block(old) | set;当how为SIG_UNBLOCK时,函数会根据set,计算新的阻塞位图,计算方式是:block(new) = block(old) & (-set);当how为SIG_SETMASK时,函数会根据set,计算新的阻塞位图,计算方式是:block(new) = set。

可以通过kill -9将进程杀死。

注意:9号和19号信号不能被阻塞。?

信号的捕捉流程

信号的处理时机:

从内核态切换到用户态的时候,会调用do_signal函数处理信号,该函数会判断是否有信号并作出相应操作:

有信号:判断当前信号是否被阻塞;阻塞的话暂时不处理;未阻塞,处理信号

处理信号时,不同的处理方式:

默认/忽略处理:直接在内核就处理结束

自定义处理:

? ? ? ? 1、执行用户在用户空间自定义的处理函数

? ? ? ? 2、调用sigruturn()函数再次回到操作系统内核

? ? ? ? 3、再次调用do_signal函数处理信号

? ? ? ? 4、调用sys_sigreturn函数回到用户空间,继续执行代码

如图所示:?

?

?常见的进入系统内核的方式:

调用系统调用函数;内存访问越界,访问空指针;调用库函数

其他扩展内容:

1、之前学习的进程等待,父进程在等待子进程退出,回收它的状态信息的时候,有两种方式,分别是:

wait接口:阻塞等待

waitpid接口:非阻塞等待,搭配循环使用

这两种方式父进程在等待子进程期间都是无法执行其他代码的,导致父进程的效率低下,我们可以使用信号的方式来解决这个问题:

我们都知道,父进程回收子进程退出信息收到的是SIGCHILD信号,因此我们可以将该信号的处理方式自定义一下,然后在接收到该信号的时候,再转去执行自定义处理方式里面的wait函数来回收子进程的退出信息。这样父进程再等待子进程退出的同时能够去执行其他代码。?

?

?

?

2、volatile关键字

作用:保证内存的可见性。每次CPU要计算的数据都是从内存中获取,拒绝编译时优化的方案(从寄存器获取)

gcc/g++的编译选项:-00 -01 -02 -03,优化级别依次增大?

加上volatile关键字后,每次都会从内存中读取数据。?

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-04-01 00:32:30  更:2022-04-01 00:35:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 23:23:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码