Linux进程概念(二)

简介: Linux进程概念(二)

进程状态

进程状态分有:

运行 新建 就绪 挂起 阻塞 等待 停止 挂机 死亡…

状态其实就是返回的整形,就像某个数字代表运行或者是阻塞等等。

普通操作系统层面理解

首先通过理论来理解操作系统的三大状态。

运行与阻塞

运行

CPU是被动接受进程的,并且操作系统会管理进程并放在内存中让CPU处理。

那么CPU是怎用什么方式去查看所有的进程呢?是定义了一个PCB类型的队列指向第一个进程的PCB,然后进行对所有进程的管理。

这个时候所有的进程是通过数据结构的方式来链接起来的,CPU会一个一个处理进程,这个时候无论被处理还是没被处理都叫做运行状态

入队的本质就是讲进程的PCB放入CPU的队列中。

注意:一个CPU只有一个运行队列!不是进程正在运行才是运行状态!运行状态用R表示!

阻塞

CPU在处理数据是非常非常快的,对比其他外设来说是这样的。

平时我们的每个进程都与外设有关,也就是说我们CPU在处理进程的时候会发现有些需要外设来配合,但是外设没有CPU快,这就导致了CPU可能还需要等这个进程和外设配合完成才行。

外设也有和CPU一样的队列,但是外设处理的很慢,也就是说会导致排队,那么CPU在处理某个进程发现他需要和外设配合,然后发现这个硬件已经开始排队了,一时半会也轮不到这个进程,也不可能让这个进程一直等着,这样非常影响效率,这个时候操作系统就会让这个进程的PCB在这个外设的队列中进行排队,这个时候R就变成了阻塞状态,等这个进程处理完成了,再去CPU的队列中重新入队,并且阻塞状态重新变为R。

这个也说明,我们的进程不仅仅要占用CPU的资源,也会随时随地占用外设资源。

也就是说,所谓的进程状态不同,也就是进入不同的队列等待资源而已!

挂起与阻塞

现在内存中有一堆的进程,假如说有很多的进程再外设队列,但是现在的内存满了,这应该怎么办呢?

这个时候操作系统就会出手了,将暂时不用的进程先放回磁盘当中,但是保留这个进程的PCB!

这样就节省了一部分空间,因为PCB几乎不占多少空间。

进程被暂时放在磁盘中,这个就叫做挂起,等内存不是那么吃紧了,操作系统就会将这个进程再放回到内存中。

这也侧面说明,阻塞不一定挂起,挂起一定是阻塞。

还有一种很极端的情况就是很多地方很多状态都需要挂起,就跟各种叠BUFF一样。

Linux是怎么做的

首先来看看Linux内核源代码对于进程状态的描述怎么说:

/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};

R代表的就是运行状态:

进程状态这里显示R+,R代表是运行状态,至于后面的+是什么,这个一会说。

如果再代码中加上调用外设会怎么样呢?

答案是会阻塞,S代表阻塞的意思。

如何让一个程序暂停?

先用kill -l查询,之前说过,这个指令是对某个进程发射信号的。

9号是结束进程,19号是暂停进程的运行,18号是继续进程的运行。

继续这个进城之后发现+号没了,然后我对左边的使用了Ctrl+C竟然没有让程序停下来,然后我又用了其他指令发现也能正常运行,只不过刚才的进程也在运行,原来是不可能发生这种情况的。

这是因为+号代表前台进程,可以通过前台关闭,但是+号没了就变成了后台进程,只能通过kill -9 ’PID‘才能让他结束。

这里T代表进程暂停的意思。

上面还有一个D,这个不方便演示,它叫做深度睡眠,只有在进程自动停下来或者是断电的情况下进程才会结束。

比如:

在Linux下,一个进程很大的数据,正在写入磁盘中,但是内存是有限的,如果内存满了,操作系统就会找到这个进程并且干掉他,那么数据就很容易丢失,这个时候就出现了深度睡眠,操作系统看到不会管他,除非这个进程运行完毕自己醒来或者是断电。

想一下,在我们调试一个程序的时候,是会先让他跑起来然后再进行调试的,那么再打断点的时候程序就会停下来:

这里 $@代表第一行:的左边 $@代表:右边。

这里的 t 被称该程序被追踪,这也是一种暂停状态。

X是死亡状态,不方便展示,因为进程结束的一瞬间所有内容都会被回收。

最后一个很重要的进程状态,他是将要死亡的一个进程,也被称为僵尸进程(Z):

一个进程在结束的时候,并不是立刻结束,而是会有返回值结果的,返回的这个结果会放进PCB中,等待父进程来拿走。

但如果没等到父进程来拿走结果,这个进程提前结束了,这时候进程本身被释放掉,但是相对应的PCB没有被释放掉,这就是僵尸进程。.

下面用一个程序来说明:

然后用这个指令来持续监视。

状态从S变成了Z,这时因为创建的子进程直接就结束了,父进程没来得及收回数据!

僵尸进程也是有一定危害的,如果父进程或者是操作系统因为一些原因没办法收回内存中的PCB是会导致内存泄漏的!

孤儿进程

如果父进程比子进程先退出,那么谁来接受子进程的返回值呢?

这种事情很常见,父进程比子进程先结束,这个子进程会被系统进程1号“收养”,这个子进程也就被称为孤儿进程。

我们让父进程结束的时候发现子进程的父进程ID变成了1,这就是系统1号进程,那么为什么父进程结束的时候看不到僵尸状态呢?因为父进程结束PCB直接就会被回收。

并且孤儿进程是后台运行的,原来的S+变成了S。

后台需要用kiil -9 PID 去关闭。

进程优先级

什么是优先级

优先级是什么呢?就是这件事可以做,但是又很多人,谁先来的问题,比如打饭需要排队,谁先来买饭就给谁一个号。

或者是平时的老人优先,军人优先等。

为什么需要分配优先级?因为资源太少了!进程很多,但是硬件很少!

Linux优先级的特点:本质就是PCB的几个整数而已。(就像排队用的号一样)

Linux下用两个整数来确认优先级的:

运行起来之后用这条指令查看状态:ps -al

UID : 代表执行者的身份

PRI :代表这个进程可被执行的优先级,其值越小越早被执行

NI :代表这个进程的nice值

进程的优先级 = 老的优先级(80) + nice(NI)

如何改变优先级

Linux中支持正在运行的进程优先级的调整。

改变优先级也就是去改变NI的值而已。

当然平时我们并不需要改变优先级,NI改变的值也是有范围的,所以改变的效果并不太明显。

Ni的范围是:[-20,19]

PRI值越小,优先级越高。

先输入:sudo top

然后按一下r

这里输入的是你进程的PID

这里输入NI值,我输入的是-100

然后q退出

再查看进程的PRI和NI

这里NI只到了-20,然后就PRI也变成了60.

为什么有范围呢?如果某个进程的PRI太小,CPU分配资源就不均衡。

其他概念

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

独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。(例如,你的QQ闪退不会影响微信正常使用,就算是父子进程也不会互相影响,只不过会需要分配更多资源)

并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行。(大型服务器会有多个CPU,多个进程在不同CPU运行)

并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进。(采用进程不断切换,分配一定时间给某个进程运行)

进程切换:

CPU当中有一套寄存器,其中一个寄存器是保存当前进程的PCB,还有一个寄存器(pc/eip)保存的是当前运行指令的下一个指令的地址,对于这个寄存器还有一些寄存器是配合分析计算指令的,还有一些寄存器是保存的都是当前进程产生的临时数据。

当然,一个进程在运行的时候是会产生临时数据的,这个时候会将临时数据放在寄存器上运作(这里要注意寄存器硬件 != 寄存器内部数据,寄存器内部的数据也叫上下文),但是我们知道进程很多,CPU只有一个,所以需要通时间片进行并发。

那么在并发的过程中,当前进程是直接切换到下一个进程吗?不是的,因为现在CPU上还有当前进程的上下文,下一个进程如果直接来,也会产生上下文,直接就会将上一个进程的上下文覆盖掉,所以需要先保存当前进程的上下文在进行切换。

等下次轮到这个进程的时候,再将这个进程的上下文放进CPU就能继续正常工作了。

总结:寄存器中的数据是属于当前进程的!寄存器被所有进程共享,寄存器中的数据是属于每个进程的上下文数据!

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