Linux——进程信号(中)

简介: Linux——进程信号(中)

第四种,软件也可以产生信号:

比如说之前的管道,读端关闭,写端也会关闭,然后导致这个软件触发条件,发生信号。

在Linux下有一个叫定时器的软件,可以设定一个闹钟,如果时间到了,会给当前进程发送编号为14的信号。(闹钟只会响一次)

参数是按照秒为单位设置一个信号。

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <cstdlib>
using namespace std;
int main(int argc, char *argv[])
{
    int count = 0;
    alarm(1);
    while(true)
    {
      count++;
        cout << count << endl;
    }
    return 0;
}

这段代码的功能是统计1S左右能让我们的计算机数据累加多少次。

其实正常来说CPU不会这么慢,可以改进一下代码:

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <cstdlib>
using namespace std;
int count = 0;
void catchSig(int sig)
{
    cout << count <<endl;
    exit(1);
}
int main()
{
    signal(14, catchSig);
    alarm(1);
    while(true)
    {
        count++;
    }
    return 0;
}

那么为什么差距这么大呢?

因为打印是一种外设输出,访问外设的时候是很慢的,需要大量的时间,第一段代码一直在通过外设进行打印,所以很慢,第二段之后结束的时候才会通过外设打印。

如果是服务器还要经过网络IO,会更慢。

”闹钟“其实就是用软件实现的:

任何一个进程都可以通过alarm系统调用在内核中设计闹钟,OS内可能会存在很多的闹钟,OS也一定要管理这些闹钟,先描述再组织。

用struct alarm类型的对象去描述各个进程的闹钟数据:

struct alarm
{
  uint64_t when;//未来的超时时间
  int type;//闹钟类型,一次性的还是周期性的
  tasl_struct *p;//和哪个进程相关
  struct alarm *next;
}

然后OS用特定堆的数据结构方式管理,struct alarm *head

OS会周期性的检测这些闹钟,如果发现超时了OS就会给对应的进程发SIGALARM信号。

上面所说的所有信号的产生,都是由OS来执行,但是信号不一定立即处理,那么是什么时候被处理的呢?

进程退出时——核心转储

先来看一段代码:

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <cstdlib>
using namespace std;
int main()
{
    while(true)
    {
        int arr[10];
        arr[100] = 106;//这里数组是越界的
    }
    return 0;
}

这里并没有显示越界的报错。

改成一千也没报错,但是i改成一万就报错了

这里是什么情况呢?因为开辟的栈区是合法的,只有到了为开辟的栈区才会进行报错。

像这种,Term这种是正常退出,而Core是退出之后还要做其他工作。

在云服务器上,默认如果进程是core退出的暂时看不到现象,想看到需要打开一个选项:

第一个core file size是0,这是云服务器默认的。

这里设置一下。

然后再次运行上面的段错误的代码:

并且还多出来了一个文件。

第一个后面多出来的core dumped就是核心转储操作,多出来的文件就是核心转储的内容。

多出来的文件.后缀是引起core问题进程的pid。

核心转储:当进程出现异常是hi后,我们将进程的对应时刻,在内存中的有效数据转储到磁盘中。(二进制临时文件)

作用就是为了更方便调试:

这里直接就帮助我们找到了问题。(这里叫做事后调试)

core-file core.xxx

信号的保存

有一个问题,如果所有信号都被捕捉了,那么这个信号是不是就无法停下来了呢?

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <cstdlib>
using namespace std;
void catchSig(int signo)
{
    cout << "信号拦截:" << signo << endl;
}
int main()
{
    for(int signo = 1; signo <= 31; signo++)
    {
        signal(signo,catchSig);
    }
    while(true)
    {
        cout << "运行中" << getpid() << endl;
        sleep(1);
    }
    return 0;
}

最后用了kill -9才将这个进程杀掉。

OS中9号信号是无法进行捕捉的。

信号其它相关概念

实际执行信号处理的动作称为信号递达。

信号从生产到递达之间的状态称为信号未决(Pending)。

进程可以选择阻塞(Block)某个信号。

被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞才执行递达的动作。

注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

并且,PCB中还有一个信号的函数指针数组,里面都是处理信号的方法。

我们使用的信号捕捉也只是将该数组中对应信号的方法给替换了,也就是替换了函数地址。

也就是说,如果要给信号产生,不妨碍他可以先被阻塞。

信号如何实现捕捉的

之前说信号只会在合适的时候才会被处理,不然就一直被保存在pending位图中。

从内核态返回用户态的时候,进行信号的处理。

我们平时是用户态,但是难免会去通过OS访问系统自身的资源和硬件资源,这个时候就要去进行系统调用才能完成:

也就是说,系统调用还要进行身份切换,会比调用用户层本身的方法慢。

所以避免频繁的使用系统调用。

并且,CPU中由寄存器会存储以下相关数据。

那么,一个进程怎么跑到OS中执行方法呢?

因为进程的独立性,所以每个进程都有一个用户级页表。

在开机的时候,操作系统要加载到内存中,因为操作系统只有一份,在内存中也只有一份,相对应的内核级页表也只有一份就够了。

CPU中也会有一个寄存器储存内核级页表,每个进程都会通过内核空间访问内核页表,然后去找到物理内存中的操作系统的代码和数据。

也就是说,进程要访问OS的接口,其实只需要在自己的地址空间上进行跳转就可以了。

如果想访问内核级数据,CPU的CR3要变成0才有权限。

那么是怎么进行切换的呢?是系统调用接口的起始位置会帮助我们进行切换。

也就会说前半段代码可能是用户态跑的,但是这里突然就变成内核态跑。

在Linux中,有一个叫Int 80 —— 陷入内核。

这个是汇编指令,这个就是修改当前进程在寄存器中CR3的身份状态。

相关文章
|
1月前
|
算法 Linux 调度
深入理解Linux操作系统的进程管理
本文旨在探讨Linux操作系统中的进程管理机制,包括进程的创建、执行、调度和终止等环节。通过对Linux内核中相关模块的分析,揭示其高效的进程管理策略,为开发者提供优化程序性能和资源利用率的参考。
69 1
|
20天前
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
88 13
|
27天前
|
SQL 运维 监控
南大通用GBase 8a MPP Cluster Linux端SQL进程监控工具
南大通用GBase 8a MPP Cluster Linux端SQL进程监控工具
|
1月前
|
运维 监控 Linux
Linux操作系统的守护进程与服务管理深度剖析####
本文作为一篇技术性文章,旨在深入探讨Linux操作系统中守护进程与服务管理的机制、工具及实践策略。不同于传统的摘要概述,本文将以“守护进程的生命周期”为核心线索,串联起Linux服务管理的各个方面,从守护进程的定义与特性出发,逐步深入到Systemd的工作原理、服务单元文件编写、服务状态管理以及故障排查技巧,为读者呈现一幅Linux服务管理的全景图。 ####
|
2月前
|
缓存 监控 Linux
linux进程管理万字详解!!!
本文档介绍了Linux系统中进程管理、系统负载监控、内存监控和磁盘监控的基本概念和常用命令。主要内容包括: 1. **进程管理**: - **进程介绍**:程序与进程的关系、进程的生命周期、查看进程号和父进程号的方法。 - **进程监控命令**:`ps`、`pstree`、`pidof`、`top`、`htop`、`lsof`等命令的使用方法和案例。 - **进程管理命令**:控制信号、`kill`、`pkill`、`killall`、前台和后台运行、`screen`、`nohup`等命令的使用方法和案例。
154 4
linux进程管理万字详解!!!
|
2月前
|
缓存 算法 Linux
Linux内核的心脏:深入理解进程调度器
本文探讨了Linux操作系统中至关重要的组成部分——进程调度器。通过分析其工作原理、调度算法以及在不同场景下的表现,揭示它是如何高效管理CPU资源,确保系统响应性和公平性的。本文旨在为读者提供一个清晰的视图,了解在多任务环境下,Linux是如何智能地分配处理器时间给各个进程的。
|
2月前
|
存储 运维 监控
深入Linux基础:文件系统与进程管理详解
深入Linux基础:文件系统与进程管理详解
90 8
|
2月前
|
网络协议 Linux 虚拟化
如何在 Linux 系统中查看进程的详细信息?
如何在 Linux 系统中查看进程的详细信息?
187 1
|
2月前
|
Linux
如何在 Linux 系统中查看进程占用的内存?
如何在 Linux 系统中查看进程占用的内存?
|
2月前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
76 4

热门文章

最新文章