网站焦点图怎么做,利用wps做网站,php做的网站安全吗,wordpress主题模块添加文章目录 #x1f4d6; 前言1. 什么是信号1.1 认识信号#xff1a;1.2 信号的产生#xff1a;1.3 信号的异步#xff1a;1.4 信号的处理#xff1a; 2. 前后台进程3. 系统接口3.1 signal#xff1a;3.1 - 1 不能被捕捉的信号 3.2 kill#xff1a;3.2 - 1 killall 3.3 ra… 文章目录 前言1. 什么是信号1.1 认识信号1.2 信号的产生1.3 信号的异步1.4 信号的处理 2. 前后台进程3. 系统接口3.1 signal3.1 - 1 不能被捕捉的信号 3.2 kill3.2 - 1 killall 3.3 raise3.4 abort3.5 alarm 4. 崩溃的本质是什么4.1 Core Dump4.1 - 1 Core Dump打开方式4.1 - 2 使用方式4.1 - 3 默认关闭的原因 前言
本章我们将讲解Linux信号这部分的内容本章将介绍信号的产生发送信号的捕捉屏蔽等操作将对信号进行一些列系统的了解与学习。目标已经确定接下来就要搬好小板凳准备开讲了… 1. 什么是信号
1.1 认识信号 在我们学习信号之前我们先来回忆一下生活中的各种信号例如红绿灯、铃声、闹钟……
我们在能够认识这些场景下的信号以及所表示的含义 即便这个信号还没有产生我们就已经具备了处理这个信号的能力。 我们早就知道了信号产生后要做什么 即便当前信号还没有产生我们已经提前知道了这个信号的处理方法。 信号是给进程发送的进程要具备处理信号的能力。
可以说程序员通过编写代码来利用操作系统提供的接口和功能实现了处理信号的能力。 该能力一定是预先已经早就有了的。 进程能够识别对应的信号。 进程能够处理对应信号。 对于进程来讲即便是信号还没有产生我们进程已经具有识别和处理这个信号的能力了。 信号的种类
使用kill -l命令罗列出来的内容叫做信号我们可以看到目前Linux系统下64种不同的类型 没有32、33、0号信号。第一批1 ~ 31普通信号第二批34 ~ 64实时信号
信号左侧的数字和右侧的名称是一回事其实都是宏大写的字母是宏名称宏的值就是左侧对应的编号。 这二者的差别是早期有实时操作系统我们现在用的是分时操作系统。 基于时间片轮转基于优先级抢占的调度算法。 1.2 信号的产生
有很多情况会产生信号
系统接口kill命令键盘产生Ctrl CCtrl \ )软件条件进程停止进程运行完退出硬件异常比如除0错误
信号发送的本质
键盘是产生了信号但是信号是操作系统发的。在位图中将对应的位置设置为1就完成了信号的发送。与其叫发送不如叫操作系统向进程写入信号。
信号都是由操作系统向系统写入的
计算机要是想向一个PCB进程发信号本质上因为操作系统是进程的管理者。可以直接以自身的身份来对进程的PCB数据结构的位图做任意修改。 崩溃现象就是底层代码引起了硬件的问题进而被操作系统识别然后操作系统将硬件问题识别成信号然后向进程发送然后终止进程。 1.3 信号的异步
何为异步 以点外卖为例当外卖到了时你可能正在忙着做其他事情外卖员给你发了条取餐消息但是你并不能立即去取。 此时我们知道自己的外卖到了知道收到了信号等手上的活忙完了再去取过一会再去处理信号。 同步和异步
当节奏会受某个因素影响时这叫同步。当节奏不会受某个因素影响时这叫异步。 信号可能在任何时候都能产生可能是用户产生也可能是操作系统产生的这个产生对进程来讲是异步的。 因为信号产生是异步的
当信号产生的时候对应的进程可能正在做更重要的事情我们进程可以暂时不处理这个信号也就是说进程可能不需要立即处理这个信号但是并不代表这个信号不会被处理
1.4 信号的处理
处理信号的三种行为
默认动作。忽略。自定义动作。 信号的处理也叫做信号的的捕捉递达处理动作。 必须记住这个信号有没有是什么信号
信号被记录在了进程的PCB当中的 有没有产生【比特位的内容1/0】 是什么信号产生【比特位的位置】 只有操作系统有这个权利能直接修改这个task_struct内的数据位图 OS是进程的管理者进程的所有的属性的获取和设置只能由OS来 无论信号怎么产生最终一定只能是OS帮我们进行信号的设置的 2. 前后台进程
Ctrl C的本质是向前台进程发送信号。 我们死循环打印Hello World在一直死循环期间我们输入命令ls并不会列出该目录下的文件名。 myproce跑起来之后再输入其他指令是没用的因为这个进程占用了前面bash所对应的终端。当前bash没法做命令行响应此时这种进程叫做前台进程。 将进程放到后台 26733是进程编号。 后台进程可以执行命令行指令但是用Ctrl C终止不了了。 jobs查看后台进程 fg 1就将该进程提至前台了再次Ctrl C就可以了。 补充 前后端混打的时候虽然会打印乱掉混乱是很正常的因为缺少访问控制信息交叉在一起。根据冯·诺依曼体系我们输入的内容一定是先被进程拿到的显示器之所以能看到是因为给显示器也拷贝了一份这叫回显。 不回显也可以的就像Linux输入密码不回显但是确实输进去了。
任务管理 在Linux中作业列表中的符号和-表示了作业的状态。
符号表示当前前台运行的作业。符号-表示当前后台运行的作业。 如果没有“和”-符号显示在作业列表中则表示当前没有前台或后台运行的作业。作业列表可能是空的也就是没有任何正在运行的作业。这通常发生在你没有在前台执行命令或将任何作业放到后台时。 bg指令 要将一个正在前台运行的作业切换到后台运行可以按下Ctrl Z这会将该作业暂停并返回到命令行界面。然后可以使用bg命令将作业放到后台继续运行此时作业会继续执行但不会再占用终端。 3. 系统接口
3.1 signal Ctrl C是向前台发送二号信号。 代码演示
#include iostream
#include unistd.h
#include signal.husing namespace std;void handler(int signo)
{cout 我是一个进程刚刚获取了一个信号: signo endl;
}int main()
{// 给该信号设置了回调捕捉自定义动作// 这里不是调用handler方法这里只是设置了一个回调让SIGINT产生的时候该方法才会被调用。// 如果不产生SIGINT该方法不会被调用// 当二号信号产生的时候才调用后面的方法。signal(SIGINT, handler);signal(3, handler);sleep(3);cout 进程已经设置完了 endl; sleep(3);while (true){cout 我是一个正在运行中的进程: getpid() endl;sleep(1);}return 0;
}注意
给该信号设置了回调捕捉自定义动作。这里不是调用handler方法这里只是设置了一个回调让SIGINT产生的时候该方法才会被调用。如果不产生SIGINT该方法不会被调用当二号信号产生的时候才调用后面的方法。
函数指针回调函数
函数指针类型允许用户对信号自定义处理忽略自定义默认。大部分信号都有默认动作而signal方法可以让进程对特定的信号自定义设置。 Ctrl C本质是给前台产生了2号信号发送给目标进程其中目标进程默认对2号信号的处理是终止自己。更改了对二号信号处理设置了用户自定义处理方法。还有一种终止进程的方法是发送3号信号。
3.1 - 1 不能被捕捉的信号 到这里我们不禁思索一番我们之前讲过kill -9 进程ID信号可以杀掉进程那我们能否将kill -9 进程ID的信号捕捉了呢
经过实验得到结论kill -9 进程ID该信号并不能被捕捉这是为了防止一些恶意进程杀不掉的情况。因为9号信号不能被设置捕捉动作。永远都是默认动作叫做管理员信号。9号信号几乎可以杀掉所有进程除了曾经讲的D状态的进程。进程状态复习-传送门 在Linux中有一些信号被称为不可捕捉信号它们无法被用户进程捕捉或处理。这些信号是
SIGKILL (信号编号为9)用于立即终止一个进程。无论进程是否希望接收该信号都无法阻止或忽略它。SIGSTOP (信号编号为19或17)用于暂停一个进程的执行。与SIGKILL类似无法被捕捉或忽略。SIGCONT (信号编号为18或19)用于继续一个被暂停的进程的执行。与前两个信号不同SIGCONT是可以被捕捉的但在默认情况下它会立即恢复进程的执行。 这些不可捕捉信号通常由操作系统或其他系统级实体发送用于管理进程的状态和行为。在正常情况下用户进程无法阻止或修改这些信号的执行。 3.2 kill
kill不仅是命令而且也是系统调用接口 向指定进程发送指定信号成功了返回0失败了返回-1。支持向任意进程发送任意信号。杀进程也是要有权限的。
不能杀掉不是自己的进程 有了上述接口再加上我们之前学的main函数的几个参数我们可以手搓一个kill指令
#include iostream
#include string
#include cstdlib
#include cstring
#include cerrno
#include unistd.h
#include signal.h
#include sys/types.husing namespace std;static void Usage(const string proc)
{cout Usage:\n\t proc signo pid endl;
}// 自己实现一个kill命令
// mykill 9 1234
int main(int argc, char* argv[])
{if (argc ! 3){Usage(argv[0]);exit(1);}if (kill(static_castpid_t(atoi(argv[2])), atoi(argv[1])) -1){cerr kill: strerror(errno) endl;exit(2);}return 0;
}3.2 - 1 killall
根据进程名字杀掉某个进程killall 进程名。
在Linux中killall命令用于终止同名进程。killall命令默认会发送SIGTERM信号编号为15信号给目标进程。不过你也可以使用参数-s或–signal来指定其他信号例如SIGKILL信号编号为9。这个命令非常有用特别是当你想要快速终止所有同名进程时。需要注意的是使用killall命令要小心确保只终止你想要终止的进程以免造成意外的影响。
3.3 raise
kill是给任意进程发任意信号raise是给自己发任意信号 进程不断地给自己发送2号信号
#include iostream
#include unistd.h
#include signal.husing namespace std;void handler(int signo)
{cout 我是一个进程刚刚获取了一个信号: signo endl;
}int main()
{// 这里没有调用对应的handler方法仅仅是注册signal(2, handler);while (true){// 每次循环都给自己发送2号信号sleep(1);raise(2);}// 每隔1秒都会收到一个2号信号return 0;
}3.4 abort
向自己发送6号SIGABRT信号
#include iostream
#include cstdlib
#include signal.h
#include unistd.husing namespace std;void handler(int signo)
{cout 我是一个进程刚刚获取了一个信号: signo endl;
}int main()
{// 这里没有调用对应的handler方法仅仅是注册signal(6, handler);while (true){sleep(1);abort();// exit(), ahort();}return 0;
}终止进程 注意
abort()是即使捕捉了但是依然会退出进程。除了9号信号不能被捕捉对6号信号进行捕捉但是依旧会退出。
硬件是在推着操作系统做一系列动作
时钟硬件 —— 给操作系统发送时钟中断。CPU主频越高调度的频率就越高效率就越高。
3.5 alarm
#include iostream
#include cstdlib
#include signal.h
#include unistd.husing namespace std;int cnt 0;void handler(int signo)
{cout 我是一个进程刚刚获取了一个信号: signo cnt: cnt endl;exit(1);
}// 信号闹钟
int main()
{// 未来一秒钟之后会超时signal(SIGALRM, handler);alarm(1);// 如果没有自定义操作默认alarm会自定义终止会收到SIGALRM信号// 统计该进程一秒钟cnt多少次while (1){cnt;// cout hello: cnt endl;}return 0;
}相比于CPU独立做计算IO非常慢。 在Linux中默认情况下当alarm定时器到期时会生成一个SIGALRM信号。 如果进程没有捕获和处理该信号那么该进程会被终止。
SIGALRM信号是用于告知进程某个定时器已经超时的信号。它通常由内核或通过使用alarm函数设置的定时器触发。当定时器超时时内核向进程发送SIGALRM信号进程可以选择捕获和处理该信号或者使用默认操作即终止进程。如果进程没有显式地设置对SIGALRM信号的处理方式通过信号处理函数或信号处理器那么SIGALRM信号将以默认操作的方式处理即终止进程。这意味着如果定时器超时并且进程没有捕获该信号进程会被终止。 4. 崩溃的本质是什么 在Linux中越界访问都叫段错误。 所谓的崩溃本质是什么呢
是该进程收到了异常信号应该叫进程崩溃了。
进程崩溃是因为收到了异常信号那么为什么会收到异常信号呢
除零问题计算是在CPU内部内有状态寄存器该寄存器是用来表征该本次计算是否出现问题。如果有问题状态寄存器中特定标志位会被计位。
C try catch
崩溃了一定会导致进程终止吗不一定 崩溃本质是什么呢 进程崩溃的本质是该进程收到了异常信号 为什么呢因为硬件异常而导致OS向目标进程发送信号进而导致进程终止的现象 除零 CPU内部状态寄存器当我们除0的时候CPU内的状态寄存器会被设置成为有报错浮点数越界CPU的内部寄存器(硬件)OS就会识别到CPU内有报错啦 1.谁干的2.是什么报错(OS - 构建信号) - 目标进程发送信号 - 目标进程在合适的时候 - 处理信号 - 终止进程。 越界 野指针 我们在语言层面使用的地址(指针)实都是虛拟地址 - 物理地址 - 物理内存 - 读取对应的数据和代码的。 如果虚拟地址有问题地址转化的工作是由(MMU(硬件) 页表(软件))转化过程就会引起问题 - 表现在硬件MMU上 - OS发现硬件出现了问题 1.谁干的2.是什么报错(OS - 构建信号) - 目标进程发送信号 - 目标进程在合适的时候 - 处理信号 - 终止进程。 MMU是内存管理单元(Memory Management Unit)的简称。 实操注意
当进程崩溃时对某个信号进行时捕捉时 要将自定义的handler函数最后exit(1);退出进程不然会一直发信号就会一直调用handler函数。 因为一般进程崩溃时操作系统会给进程发送对应的信号并终止进程。 如果不加上最后的退出进程会一直打印刷屏。一旦我们不进行信号捕捉会直接终止。而我们捕捉之后如果没有对信号做处理没有终止进程的话会一直刷屏进程没有被终止。
因为没有解决这个问题这个异常一直都在所以操作系统一直给进程发信号所以刷屏了。
4.1 Core Dump Core Dump会把进程在运行中对应的异常上下文数据core dump到磁盘上方便调试。 发上云服务器是设置成0的禁止发生core dump(一般是关掉的)但是可以打开。
4.1 - 1 Core Dump打开方式 Core不光光要终止还要发生Core dump。 8号信号本身就要产生core文件的然后指令发现多了一个文件里面是乱码。 当一个进程异常退出时收到了某些信号系统为了便于用户调试会告诉用户触发core dump机制core dump机制叫做核心转储。
4.1 - 2 使用方式
代码演示
#include iostream
#include cstdio
#include cstdlib
#include signal.h
#include unistd.h
#include sys/types.h
#include sys/wait.husing namespace std;int main()
{ pid_t id fork();if (id 0){// 子进程int *p nullptr;*p 1000; // 野指针问题exit(1);}// 父进程int status 0;// nullptr, NULL, 0, \0 0;waitpid(id, status, 0); // nullptr// core dump表明当前进程在退出时是否发生core dumpprintf(exitcode: %d, signo: %d, core dump flag: %d\n,(status 8) 0xFF, status 0x7F, (status 7) 0x1);return 0;
}核心转储(Core Dump)是指在程序运行过程中发生了严重错误导致程序崩溃时系统将程序内存的完整快照保存到一个核心转储文件中。 这个文件包含了程序崩溃时的内存状态、寄存器的内容以及其他相关的调试信息。核心转储文件主要用于程序崩溃分析和调试目的。通过分析核心转储文件开发人员可以了解程序崩溃时的内存状态定位错误的原因并进行问题排查和修复。核心转储文件通常具有可读性较低的二进制格式需要使用调试工具或分析器来解析和分析。在许多操作系统上默认情况下当程序崩溃时会自动生成核心转储文件。开发人员也可以在程序中通过设置相应的参数或使用调试工具来控制核心转储的生成及其行为。需要注意的是由于核心转储文件可能会包含敏感信息如内存中的数据因此在进行排查和分析时需要遵守相应的隐私保护规定并确保核心转储文件的安全性。 生成的Core Dump文件很大 Core Dump一般配台gdb使用 每次执行出错都会产生core dump文件这种调试策略叫做事后调试。
4.1 - 3 默认关闭的原因
云服务器关掉的原因 因为如果大型程序一旦代码有问题会自动重启程序如果一重启就挂掉就会产生core文件所以一直重启就会产生大量的core文件就很大概率将磁盘空间被打满此时就会危及到操作系统正常工作了。