目录
1. 什么是进程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在系统中,进程是担当分配系统资源(如CPU时间,内存等)的实体。
2.进程的载体
那么,我们如何描述进程,它又是怎么被我们操作的呢?
进程的信息被存放在一个叫做进程控制块的数据结构中,它也是进程属性的集合,我们称之为 PCB(process control block)。
在Linux中,我们使用task_struct这个结构体来进行进程的信息存储,它是PCB的一种,它存储了有关进程的以下信息:
1.标示符 : 描述本进程的唯一标示符,用来区别其他进程。2.状态 : 任务状态,退出代码,退出信号等。3.优先级 : 相对于其他进程的优先级。4.程序计数器 : 程序中即将被执行的下一条指令的地址。5.内存指针 : 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针6.上下文信息 : 进程执行时处理器的寄存器中的数据 [ 休学例子,要加图 CPU ,寄存器 ] 。7. I / O 状态信息 : 包括显示的 I/O 请求 , 分配给进程的 I / O 设备和被进程使用的文件列表。8. 记账信息 : 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。9. 其他信息
但是,在一个进程,不仅仅只有其属性,还应该有其具体的行为,比如一些实现自身操作的代码和数据,因此,我们可以理解为:
进程 = PCB数据结构对象 + 代码数据
其中,PCB数据结构对象存储的是进程的所有属性。
3.操作进程
在学习操作进程前,我们必须了解两个概念,PID是什么?PPID是什么?
其中PID是此进程的唯一标识符,而PPID则是其父进程的唯一标识符。
什么叫做唯一标识符,唯一标识符是操作系统识别不同进程的唯一依据,相当于每个学生在学校的学号,每个人都是不一样的。但是多个进程的PPID可能是相同的,因为他们可以拥有同一父进程。
3.1. 查看进程
在Linux中,进程的信息都存储在 /proc 系统文件夹中
(1)查看所有进程信息
ls /proc/
(2)查看指定进程信息
我们在使用Linux编写程序,经常需要找到自己编写的程序生成的可执行程序的pid
这个时候我们可以使用
ps aux | grep 文件名
来对进程信息进行过滤,得到我们需要的文件进程信息。
如我对test.exe文件进行查找,得到结果如下
其中 14035 是其 PID ,其他部分后面再说。
(3)创建进程
进程的创建我们常常使用 fork 完成, fork的特点是,它返回两次值,
如果创建成功,他给子进程返回0,给父进程返回创建的子进程PID,
创建失败时,在父进程中返回-1,不创建子进程,并且errno被适当地设置
我们编写以下代码进验证:
int main()
{
pid_t pid =fork();
if(pid==0)
printf("Child: PID: %d ,PPID : %d\n",getpid(),getppid());
else if(pid>0)
printf("Father PID: %d ,PPID : %d\n",getpid(),getppid());
else
printf("fork error");
return 0;
}
得到如下结果:
4.进程状态
总览
进程的状态总的可以分为三种:1.运行状态 2.阻塞状态 3.挂起状态
要了解这三种状态,我们要先了解,进程在操作系统中是以进程队列的方式进行调度的。
进程先以PCB对象的形式进行属性集合,在进入进程队列中进行在CPU上的排队。
运行状态:当我们的进程进入了进程队列进行排队时,我们称之为运行状态。
阻塞状态:若进程处于等待过程(如等待scanf输入),称之为阻塞状态。
挂起状态:当进程只有PCB对象在进程队列中,数据还处于外设中,称之为挂起状态。
其次我们要了解,进程一定运行完了才出进程队列吗?
我们知道,如果真的是这种情况,那一个进程出问题,岂不是后续所有进程都无法进行了,因此,我们得有一个其他出队列方法,这就是时间片。每一个进程都有一个独立的时间片,当其在CPU上的运行时间超过时间片,将强制终止进程,这也就保证了后续进程的运行。
接下来我们对进程状态进行细分:
(1)运行态 R
运行态就是进程处于运行中的状态。
(2)阻塞态 S
阻塞态与前面讲的阻塞状态是一样的
(3)深度睡眠 D
深度睡眠是阻塞状态的一种,它的特点是进程处于等待中且不能够被杀进程,并且不能够被唤醒,当进程处于深度睡眠,一般系统内存压力已经接近崩溃。
(4)暂停态 T
与S态不同的是,T状态可能是在等待数据(scanf...),也有可能是被控制暂停(如调试程序到达断点处为T状态)
(5)僵尸态 Z
当进程被杀死时,并不是直接就给清除了,而是要等待其父进程读取其退出状态代码,如果这个操作没有进行完成,就会使其进入Z状态,因此,如果子进程结束,父进程还在运行,就会使子进程进入Z状态。僵尸态的危害是极大的,后续将会进行讲解。
(6)死亡态 X
5.僵尸进程和孤儿进程
僵尸进程的危害
前面讲过,僵尸进程就是子进程的返回状态代码没有被父进程完成接收从而产生的一种状态。
进入僵尸态的进程,如果迟迟得不到处理,就会导致其PCB对象元组存在,造成内存的浪费。
当一个父进程有很多子进程都变成的僵尸态,对于内存的开销是极大的,就会造成内存泄漏。
孤儿进程
什么是孤儿进程,简单来说就是没有父进程的的进程。当一个子进程的父进程提前退出,这个子进程就称之为孤儿进程,这时没有父进程的子进程毫无疑问会进入僵尸态,我们如何解决这个问题呢?
在一个进程成为孤儿进程时,会由1号进程(PID为1) init 进行收养,就不会产生一定进入僵尸态的问题了。
6.进程优先级
在日常生活中,为了效率最大化,我们常常要选择性地先进行某些急事,再进行一些无关紧要的小事,在计算机中,为了使CPU效率最大化,我们也采用这个方法,但是计算机衡量进程急不急的标准是进程优先级。
(1)查看优先级
我们输入
ps -l
就能够得到进程的一些信息,如下:
其中的 PRI 代表的就是进程优先级的一个值。
在Linux中,PRI默认为80,其值越小表示进程的优先级越高。
(2)修改优先级
由上图我们可以看到一个 NI 值,我们称之为nice值,他的默认值为0
当我们修改优先级时,实际上就是修改nice值,这是为什么呢?
这是因为, 进程优先级 = PRI + NI
因此通过修改nice值,我们可以间接修改进程优先级
其中 ,nice值的取值范围为 [ -20 , 19 ] ,当大于19,取值为19,小于-20取值为-20
修改nice值,我们使用的是top 指令,先输入top
再输入 ‘r' ,再输入PID值,最后输入相应的nice值就可以完成nice值的修改。