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就能继续正常工作了。

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

相关文章
|
3天前
|
消息中间件 算法 Linux
【Linux】详解如何利用共享内存实现进程间通信
【Linux】详解如何利用共享内存实现进程间通信
|
3天前
|
Linux
【Linux】命名管道的创建方法&&基于命名管道的两个进程通信的实现
【Linux】命名管道的创建方法&&基于命名管道的两个进程通信的实现
|
3天前
|
Linux
【Linux】匿名管道实现简单进程池
【Linux】匿名管道实现简单进程池
|
3天前
|
Linux
【Linux】进程通信之匿名管道通信
【Linux】进程通信之匿名管道通信
|
3天前
|
存储 Linux Shell
Linux:进程等待 & 进程替换
Linux:进程等待 & 进程替换
30 9
|
3天前
|
存储 Linux C语言
Linux:进程创建 & 进程终止
Linux:进程创建 & 进程终止
27 6
|
3天前
|
Linux 数据库
linux守护进程介绍 | Linux的热拔插UDEV机制
linux守护进程介绍 | Linux的热拔插UDEV机制
linux守护进程介绍 | Linux的热拔插UDEV机制
|
3天前
|
Unix Linux 调度
linux线程与进程的区别及线程的优势
linux线程与进程的区别及线程的优势
|
3天前
|
Linux 调度 C语言