【Linux】进程信号(上)(一)

简介: 【Linux】进程信号(上)

1.信号概念理解

信号产生

什么叫做信号呢?

生活当中认为是信号的是:红绿灯 闹钟 下课铃 鸡叫 手势

1.当红灯亮的时候, 你会停下来 即匹配的动作

那为什么会有这个匹配动作呢?

因为曾经有人培养过你

所以信号没有被产生,也知道怎么该处理它


2.我们能够认识并处理一个信号,是能因为识别这个信号的


若进程就是我,信号就是一个数字,进程在没有接收信号的时候,它早就知道一个信号该如何处理了

程序员在设计进程的时候,早就已经设计了对信号的识别能力


3.因为信号可能随时产生,所以在信号产生前,我可能正在做优先级更高的事情,我可能不能立马处理信号

要在后续合适的时候进行处理


如:你点了一份外卖,因为你不确定外卖什么时候到,所以开了一把游戏,当外卖小哥给你打电话说外卖到了时,游戏还没打完,所以你跟外卖小哥说等一会,马上到,然后继续打游戏,直到游戏打完,才去取外卖


信号保存


4a18d0e8648c4c058e394f50fbc0031f.png

在信号产生和信号处理之间,存在时间窗口,因为没办法直接处理,需要等待后续处理

在时间窗口期间,需要被保存起来


进程收到信号的时候,如果没有立马处理这个信号,需要进程具有记录信号的能力


信号的产生对于进程来讲是异步的


异步为两者互相做自己的事,互不干扰

如:你正在上课,外卖小哥给你打电话告诉你快递到了,因为快递有重要的东西,所以你不得不现在去取,但是在你取快递的过程中,依旧在上课,上课与你取快递两件事情互不干扰


进程该如何记录对应产生的信号?记录在哪里?


可能同时收到很多信号,已经被产生但尚未处理,所以需要在时间窗口内,将这些信号保存,同时也应该将其进行管理

而管理的本质是先描述,在组织

那如何描述一个信号呢? 用什么数据结构管理这个信号呢?


输入 kill -l 查看信号列表


7845a99154624b22b53ba3cf89376d17.png

可以发现在31 和34之间没有信号存在,说明信号被划分为两部分,1-31以及34-64

34-64称之为实时信号,

1-31称之为普通信号,是目前要学习的信号

数字实际上是真正的信号,而大写的名称是宏


实时操作系统

当前主流的操作系统分为实时和分时,

分时像Linux、windows操作系统,基于时间片操作器调度的,强调的是公平调度

实时 像汽车的车载系统的辅助驾驶

特点为若来一个任务,就必须优先级较高的将该任务立马处理,强调的是高响应

普通信号 ,只保存有无产生,只需在合适的时候处理信号即可


可以通过0代表没有产生,1代表产生

1-31刚好是32个比特位,所以使用位图结构管理信号

而进程使用task_struct(PCB) 内部必定要存在一个位图结构,用int表示


e775d28d82ab45da82ba18967f920850.png


从低到高的比特位,依次对应1-31 信号

发送信号的本质是写入信号,直接修改特定进程的信号位图中的特定比特位,0变成1即可

比特位的位置,称之为信号的编号

比特位的内容,表示是否收到该信号


信号处理

默认处理信号的方式:

1.默认动作

2.忽略信号

3.用户自定义动作

如:拿到快递,共有三种选择

1.执行默认动作把快递打开 2.忽略快递 3. 执行自定义动作(如快递内是零食,送给你的女朋友)

2. 信号的产生

在vscode中,创建makefile文件

mysignal:mysignal.cc
    g++ -o $@ $^
.PHONY:clean
clean:
    rm -f mysignal

创建 mysignal.cc(以cc结尾是cpp) 文件

会一直循环打印一句话,并当前进程的包含pid值

#include<iostream>
#include<unistd.h>
using namespace std;
int main()
{
   while(true)
   {
    cout<<"我是一个进程,我正在运行...,pid值:"<<getpid()<<endl;
    sleep(1);
   }
    return 0;
}

复制SSH渠道创建终端2,在保证运行终端1的可执行程序的情况下,

在终端2中输入 kill -9 +pid值 ,终止了终端1中运行的程序

9b4b44332c1f42a79e378d5f248f36a5.png


8a69448be7cd4f988d64ed882b076810.png


实际上 在键盘中输入 CTRL C ,终止运行程序,本质也是向对前台进程发送信号


2dbb85a1a0c841429f8c8e36cb6ca8ac.png


Linux通过远程终端访问时,只允许一个进程处于前台,默认情况是bash,

所以在自己的程序运行时输入指令没有任何反应


证明输入 CTRL C 就是向前台进程发送信号

输入 man 2 signal 指令


82e0a96dcaac4402a4f0e9fd513d8caa.png


第二个是一个函数指针 将 void(*) (int) typedef 命名为 sighandler_t

signal 函数的第一个参数 是 signsum 代表信号编号

第二个参数 是 handler 代表哪一个进程调用了signal,使指定信号不在执行默认动作,而是执行该函数指针指向的方法


输入 CTRL C 相当于发送 2号信号


修改 mysignal.cc文件内容,并运行程序 发现输入 CTRL C 指令无法结束程序


77dc6362ec1d40f7ac58ef211a390ddb.png

91444f691e8f400298b8aedf8468f0dd.png

同样在终端2中输入 kill -2 pid值,也无法结束运行程序

说明对于2号信号 ,进程的默认方法是终止进程

signal 可以进行对指定动作的信号设定自定义处理动作

signal 函数内部参数传递的理解


76facb1bf7794bf0ba3eed8ebe3be66c.png

当signal(2,handler)调用完这个函数时, handler方法没有被调用,只是发生了回调

handler作为函数的地址传过去 作为参数被函数指针接收,再通过函数指针找到handler函数 完成调用

在操作系统内部,把对应的自定义方法的地址保存起来了


handler方法什么时候被调用?

当2号信号产生的时候

如: 你小时候总喜欢在家里调皮,你老爸不管你,认为这是很正常的事情,所以你认为这是默认动作,但是你的老妈看见你调皮,就告诉你说如果下次再看见你调皮,就揍你,

所以再有调皮捣蛋事情发生,不会像你老爸那样什么都不管,你老妈会揍你

是在下次调皮发生的时候,才揍你


对于信号自定义动作的捕捉问题

默认对2号信号的处理动作:终止进程

输入 man 7 signal 指令

f544f273fefa4d019f1c072dd60c83cf.png

2号信号的动作是 Term(终止)

用signal(2,handler),是在执行用户动作的自定义捕捉


878ff5b58f9f4f7ba701282aff92ad73.png


CTRL \ 代表3号信号 ,此时虽然2号信号被置为自定义动作了,但是三号信号还没有,所以依旧能终止进程


修改mysignal.cc文件内容,加入对于3号信号的自定义动作


48a1dacbcb8b41419f3a61d69d18c61f.png

89a3e6623761443482158a12e81eb96f.png


再次运行可执行程序时,发现使用CTRL \ 也会调用自定义动作


77c71f72cb314752af5caf0e0f2c856c.png


可以给所有信号设置同一个处理函数


若修改mysignal.cc文件内容,将1-31的所有普通信号都进行自定义动作捕捉

9dc39ce952ef4734b12af33213ef6529.png


15976f75b1a84035b374efbd14fe60ba.png


可当运行可执行程序时,在终端2中使用 kill -9 pid值 方式依旧可以干掉进程


9号信号被称为管理员信号,不可被自定义,只能执行默认动作


相关文章
|
23天前
|
网络协议 Linux
Linux查看端口监听情况,以及Linux查看某个端口对应的进程号和程序
Linux查看端口监听情况,以及Linux查看某个端口对应的进程号和程序
99 2
|
23天前
|
Linux Python
linux上根据运行程序的进程号,查看程序所在的绝对路径。linux查看进程启动的时间
linux上根据运行程序的进程号,查看程序所在的绝对路径。linux查看进程启动的时间
40 2
|
17天前
|
Linux C语言
C语言 多进程编程(四)定时器信号和子进程退出信号
本文详细介绍了Linux系统中的定时器信号及其相关函数。首先,文章解释了`SIGALRM`信号的作用及应用场景,包括计时器、超时重试和定时任务等。接着介绍了`alarm()`函数,展示了如何设置定时器以及其局限性。随后探讨了`setitimer()`函数,比较了它与`alarm()`的不同之处,包括定时器类型、精度和支持的定时器数量等方面。最后,文章讲解了子进程退出时如何利用`SIGCHLD`信号,提供了示例代码展示如何处理子进程退出信号,避免僵尸进程问题。
|
18天前
|
NoSQL
gdb中获取进程收到的最近一个信号的信息
gdb中获取进程收到的最近一个信号的信息
|
24天前
|
消息中间件 Linux
Linux进程间通信
Linux进程间通信
32 1
|
25天前
|
Linux 调度
Linux0.11 信号(十二)(下)
Linux0.11 信号(十二)
19 1
|
25天前
|
C语言
Linux0.11 系统调用进程创建与执行(九)(下)
Linux0.11 系统调用进程创建与执行(九)
20 1
|
7天前
|
存储 监控 安全
探究Linux操作系统的进程管理机制及其优化策略
本文旨在深入探讨Linux操作系统中的进程管理机制,包括进程调度、内存管理以及I/O管理等核心内容。通过对这些关键组件的分析,我们将揭示它们如何共同工作以提供稳定、高效的计算环境,并讨论可能的优化策略。
15 0
|
19天前
|
Unix Linux
linux中在进程之间传递文件描述符的实现方式
linux中在进程之间传递文件描述符的实现方式
|
20天前
|
开发者 API Windows
从怀旧到革新:看WinForms如何在保持向后兼容性的前提下,借助.NET新平台的力量实现自我进化与应用现代化,让经典桌面应用焕发第二春——我们的WinForms应用转型之路深度剖析
【8月更文挑战第31天】在Windows桌面应用开发中,Windows Forms(WinForms)依然是许多开发者的首选。尽管.NET Framework已演进至.NET 5 及更高版本,WinForms 仍作为核心组件保留,支持现有代码库的同时引入新特性。开发者可将项目迁移至.NET Core,享受性能提升和跨平台能力。迁移时需注意API变更,确保应用平稳过渡。通过自定义样式或第三方控件库,还可增强视觉效果。结合.NET新功能,WinForms 应用不仅能延续既有投资,还能焕发新生。 示例代码展示了如何在.NET Core中创建包含按钮和标签的基本窗口,实现简单的用户交互。
43 0