【Linux修炼】8.进程概念(二)

简介: 【Linux修炼】8.进程概念(二)

4.两种特殊的进程



4.1僵尸进程


上述已经提到过僵尸状态的进程的概念,那么在这里就详细演示一下僵尸进程的具体面貌:(代码)

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
int main()
{
    int id = fork();
    if(id > 0)
    {
        while(1)
        {
            printf("我是父进程,pid: %d, ppid: %d\n", getpid(), getppid());
            sleep(1);
        }
    }
    else if(id == 0)
    {
        while(1)
        {
            printf("我是子进程,pid: %d, ppid: %d\n", getpid(), getppid());
            sleep(1);
        }
    }
    else 
    {
        perror("fork fail");
        exit(-1);
    }
    return 0;
}


我们发现,通过sleep,为4044的子进程被杀掉了,此时父进程并没有处理子进程,因此出现了default(失效)并且子进程变成了Z状态,并且左侧也验证了只剩下父进程,并没有子进程的存在了!如果父进程一直不对这个子进程进行收取,那么这个子进程就会变成僵尸进程。


微信图片_20230225131125.png


4.2孤儿进程


1. 什么是孤儿进程?


上述我们提到,如果一个子进程被杀,那么其暂时就会处于僵尸状态,如果没有父进程回收就会变成僵尸进程。那如果是父进程被杀,父进程和子进程又会发生什么呢?事实上,父进程被杀,即父进程比子进程先退出,那么剩下的子进程就叫做孤儿进程。 这种现象也确实存在。


2.孤儿进程的表现形式


我们知道,如果一个进程变成了僵尸进程,其进程状态就会变成T,那我们来看看孤儿进程是如何表现的。


  1. 首先,我们仍然展示一下具体代码:(和僵尸进程中的代码一致)


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
int main()
{
    int id = fork();
    if(id > 0)
    {
        while(1)
        {
            printf("我是父进程,pid: %d, ppid: %d\n", getpid(), getppid());
            sleep(1);
        }
    }
    else if(id == 0)
    {
        while(1)
        {
            printf("我是子进程,pid: %d, ppid: %d\n", getpid(), getppid());
            sleep(1);
        }
    }
    else 
    {
        perror("fork fail");
        exit(-1);
    }
    return 0;
}


接下来,复制SSH渠道,杀掉父进程,观察子进程的状态。(父进程也关注一下)动图展示:


微信图片_20230225131240.gif

结果:

微信图片_20230225131245.png

我们发现,有三处发生了变化,其一是父进程被杀之后,变成了S状态,但是这样不就与我们之前的僵尸状态违背了吗?为什么不是T状态呢?事实上我们在上述僵尸状态中讲过,在被父进程回收之前就是T状态,而这个父进程被杀掉,也有其相应的父进程,这个父进程的父进程就是bash,bash相比较普通的父进程,bash进程将他的子进程进行了及时的回收,而这个父进程却不会对其子进程进行及时的回收。因此对比之下bash进程比一般的父进程更加负责。


其二就是我们子进程的状态,由S+变成了S进程,即从前台进程变成了后台进程,这就是孤儿进程最明显的变化,变成后台进程后不能通过ctrl c快捷键暂停,而只能通过kill结束进程(当然,断电处理也可以,但是没必要)


其三我们发现,子进程的PPID也就是这个子进程的父进程因为被杀掉而变成了1,而这个1所对应的其实就是操作系统,即父进程被杀掉之后,这个子进程被操作系统所领养,操作系统就变成了他的父进程,这也正对应了冯诺依曼体系中的进程被操作系统所管理。如果不领养,那么当这个子进程被杀掉时,就会因为没有后续处理从而将变成僵尸进程,这是整个体系都不愿看到的结果,因此操作系统必须领养。



5.进程优先级(了解范畴)



对于进程优先级,我们采取三个问题将这个概念解释清楚:


1. 什么叫做优先级?


只凭字面意思来说,优先级和权限有没有区别呢?答案是一定有的,即权限是能做或者不能做的问题,而优先级是先做和后做的问题。


2. 为什么会存在优先级?


那为什么会存在优先级呢?那是因为在一定范围内的资源是有限的,为了获得这个资源就必须赶在其他人的前面,否则就有可能最后什么也捞不到。举个例子:我们知道在一个内存中有许多的进程,但是CPU只有一个,这个时候进程为了能够先执行就会产生优先级的概念,即重要的进程先运行,其他的进程后运行。


3. Linux优先级的特点


在Linux操作系统中,在ps ajx 选项中出现的PRI(priority)下的数字就是所谓的优先级,即这个数字和我们现实中的排名一样,数值越低,优先级就越高。而这个数值PRI = 基础数值(80) + nice值,(NI)nice值是可以进行修改的,其修改区间为[-20,19],因此PRI的范围为[60, 99]。


仍然是利用孤儿进程的代码:

演示:通过指令ps -l PID


微信图片_20230225131356.png

我们发现,初始状态下,PRI和NI的值为80和0,加起来就是基础数值。

接下来进行修改:

通过如下指令:进入top后按“r”–>输入进程PID–>输入nice值

第一步:sudo top(改变优先级需要提权)

微信图片_20230225131400.png


第二步:输入r,输入对应要修改优先级进程的PID,回车


微信图片_20230225131443.png

第三步:输入修改之后的NI值。回车。

微信图片_20230225131446.png

这样就修改完成了,接下来我们看一看结果:

微信图片_20230225131449.png

这样其PRI就变成了80+19 = 99。


6.进程的其他概念



竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级

独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰

并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行

并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发(一段时间采用:时间片轮转的方式)


7.进程切换



在定义之前,我们需要举例引入进程切换的概念,对于我们常用的手机、电脑等,一般只有一个CPU,我们知道一个CPU一次只能运行一个进程,但是我们发现,在电脑上,我们可以在打开PDF的同时,去浏览一些其他网页,即同一个时间段内,多个进程可以被CPU同时运行,这是为什么呢?事实上这就是进程切换的效果。


进程切换的理解: 由于Linux的CPU一次只能运行一个进程,但是我们一个时间段内却可以运行多个进程,因为CPU是足够快的,因此我们人感觉的一瞬间就相当于CPU的一个时间段,想一想1ms对于人来说算是一瞬间,但是CPU却是以纳秒为单位计时的,因此在我们自身感觉到的一瞬间也就是CPU的一个时间段内,会将执行的多个进程按照一定的周期分别运行,一个运行到固定周期之后就强行拉入运行队列的末尾等待,就这样直到完成所有执行的进程,这就是进程之间在一定的时间内相互切换,叫做进程切换。而所谓的周期就是时间片。(并发中提到)


进程的上下文保护:


当CPU在进行进程切换的时候,要进行进程的上下文保护,当进程在恢复运行的时候,要进行上下文进程的恢复!


上下文是什么呢?


进程在运行时会产生非常多的临时数据,同时CPU中存在一套寄存器硬件,当进程运行时,进程的PCB会被放入CPU内的寄存器中,此时CPU就可以通过进程PCB(暂时理解成PCB)得到进程代码数据的地址;CPU在运行进程时所产生的大量的临时数据也都会被保存在寄存器中;因此在进行进程切换时需要进行进程的上下文保护与上下文恢复,进程停止运行时将寄存器里面的数据保存起来,进程重新运行时将保存的数据再放入到寄存器中;所以进程的上下文就是一个进程完成他的时间片后在CPU中所保存的临时数据。



相关文章
|
6月前
|
并行计算 Linux
Linux内核中的线程和进程实现详解
了解进程和线程如何工作,可以帮助我们更好地编写程序,充分利用多核CPU,实现并行计算,提高系统的响应速度和计算效能。记住,适当平衡进程和线程的使用,既要拥有独立空间的'兄弟',也需要在'家庭'中分享和并行的成员。对于这个世界,现在,你应该有一个全新的认识。
249 67
|
5月前
|
NoSQL Linux 编译器
GDB符号表概念和在Linux下获取符号表的方法
通过掌握这些关于GDB符号表的知识,你可以更好地管理和理解你的程序,希望这些知识可以帮助你更有效地进行调试工作。
212 16
|
5月前
|
Web App开发 Linux 程序员
获取和理解Linux进程以及其PID的基础知识。
总的来说,理解Linux进程及其PID需要我们明白,进程就如同汽车,负责执行任务,而PID则是独特的车牌号,为我们提供了管理的便利。知道这个,我们就可以更好地理解和操作Linux系统,甚至通过对进程的有效管理,让系统运行得更加顺畅。
135 16
|
5月前
|
Unix Linux
对于Linux的进程概念以及进程状态的理解和解析
现在,我们已经了解了Linux进程的基础知识和进程状态的理解了。这就像我们理解了城市中行人的行走和行为模式!希望这个形象的例子能帮助我们更好地理解这个重要的概念,并在实际应用中发挥作用。
107 20
|
4月前
|
监控 Shell Linux
Linux进程控制(详细讲解)
进程等待是系统通过调用特定的接口(如waitwaitpid)来实现的。来进行对子进程状态检测与回收的功能。
84 0
|
4月前
|
存储 负载均衡 算法
Linux2.6内核进程调度队列
本篇文章是Linux进程系列中的最后一篇文章,本来是想放在上一篇文章的结尾的,但是想了想还是单独写一篇文章吧,虽然说这部分内容是比较难的,所有一般来说是简单的提及带过的,但是为了让大家对进程有更深的理解与认识,还是看了一些别人的文章,然后学习了学习,然后对此做了总结,尽可能详细的介绍明白。最后推荐一篇文章Linux的进程优先级 NI 和 PR - 简书。
115 0
|
4月前
|
存储 Linux Shell
Linux进程概念-详细版(二)
在Linux进程概念-详细版(一)中我们解释了什么是进程,以及进程的各种状态,已经对进程有了一定的认识,那么这篇文章将会继续补全上篇文章剩余没有说到的,进程优先级,环境变量,程序地址空间,进程地址空间,以及调度队列。
81 0
|
4月前
|
Linux 调度 C语言
Linux进程概念-详细版(一)
子进程与父进程代码共享,其子进程直接用父进程的代码,其自己本身无代码,所以子进程无法改动代码,平时所说的修改是修改的数据。为什么要创建子进程:为了让其父子进程执行不同的代码块。子进程的数据相对于父进程是会进行写时拷贝(COW)。
81 0
|
7月前
|
Linux 数据库 Perl
【YashanDB 知识库】如何避免 yasdb 进程被 Linux OOM Killer 杀掉
本文来自YashanDB官网,探讨Linux系统中OOM Killer对数据库服务器的影响及解决方法。当内存接近耗尽时,OOM Killer会杀死占用最多内存的进程,这可能导致数据库主进程被误杀。为避免此问题,可采取两种方法:一是在OS层面关闭OOM Killer,通过修改`/etc/sysctl.conf`文件并重启生效;二是豁免数据库进程,由数据库实例用户借助`sudo`权限调整`oom_score_adj`值。这些措施有助于保护数据库进程免受系统内存管理机制的影响。
|
7月前
|
存储 Linux 调度
【Linux】进程概念和进程状态
本文详细介绍了Linux系统中进程的核心概念与管理机制。从进程的定义出发,阐述了其作为操作系统资源管理的基本单位的重要性,并深入解析了task_struct结构体的内容及其在进程管理中的作用。同时,文章讲解了进程的基本操作(如获取PID、查看进程信息等)、父进程与子进程的关系(重点分析fork函数)、以及进程的三种主要状态(运行、阻塞、挂起)。此外,还探讨了Linux特有的进程状态表示和孤儿进程的处理方式。通过学习这些内容,读者可以更好地理解Linux进程的运行原理并优化系统性能。
239 4