目录
一、进程的概念
传统的教科书上对进程的解释一般都是"运行起来的程序"或"内存中的程序",概念没错,但是探究进程其本质,无非就是"程序自身的代码和数据"+"内核数据结构"。
1.程序代码和数据:
这部分就是指我们编译出来的比如代码段、数据段以及栈、堆等等,这部分是进程自己的内容,也就是进程要跑的"业务"。
2.内核数据结构:
这部分就是操作系统为了管理这个进程,必须要记住的信息,比如PID、状态(就绪、运行、阻塞...)、优先级、打开的文件、地址空间、寄存器上下文(切出去再切回来要恢复)。而在Linux的源码中,实现了这一堆功能的是在结构体task_struct(也就是PCB,又称进程控制块)中。
总结来讲就是,程序本身只是"静态文件",躺在硬盘里。只有当操作系统给它套上一个PCB(task_struct),它才变成进程。
二、操作系统为什么要管理进程?
首先操作系统能同时运行很多程序 -> 就有多个进程同时存在 -> 而每一个进程都需要加载到内存中,也就是需要占内存、占CPU、占资源 -> 那么就必须要有人管,那就是操作系统 -> 操作系统管理进程的唯一手段,就是PCB。
PCB就是进程在内核中的"身份证+户口本+档案"。没有PCB,操作系统就看不见这个进程,因此有多少个进程,内核就有多少个PCB。同时,操作系统调度、切换、暂停、恢复进程,只看PCB,不看代码。
三、初步理解进程、并发、时间片、上下文切换
进程本质就是一个程序在运行,系统会存在很多进程但是CPU只有一个,因此进程就存在了优先级(优先级属于进程信息,记录在PCB当中),一个接一个地被执行,但是CPU又不可能把一个进程的所有代码都执行完才进行下一个进程,否则一旦代码出现了一个死循环那电脑不久卡死机了,因此一个进程没执行完,就可能把CPU让出去了,那么进程到底执行多久呢?这里就要涉及到时间片的概念了,通俗来讲就是CPU执行一个进程是有固定的时间,这个时间结束后CPU就会执行下一个进程,周而复始,称为"时间片轮转"。那么每次都只是执行一段,CPU如何记忆每次执行到哪了呢?总不能每次都重头再来把?那就没意义了,其实CPU当中存在一套寄存器,同一时刻,寄存器只装当前正在跑的进程,该进程结束后,要对进程数据的上下文进行保存到PCB当中,然后再执行下一个进程,再保存下一个进程的上下文数据,周而复始,再次执行到相同的进程后,根据其保存的数据锁定上一次运行到的位置,继续执行,再更新数据,CPU内的寄存器硬件,可以在不同时间段,保存不同进程的数据,每一个进程的PCB的内容都是私有的,因此会有很多PCB来同时存储多个进程的数据。
四、获取进程的标识符
每一个进程都有自己独特的标识符,那么我们应当如何获取呢?想要获取自己的task_struct结构内部的属性值,OS就必须给我提供一个系统调用,以获取进程自己的PID!
这个系统调用接口就是"getpid (get process identification)"。它包含在两个头文件中,分别是"#include <sys/types.h>"和"#include <unistd.h>"。
调用方法就是 pid_t getpid(void),pid_t其实就是宏定义的int类型。
下来我们写一个程序,来获取进程的PID。

写好之后我们出来运行一下,看看是否能得到PID

很显然,我们是可以得到的,且进程运行过程中其PID是不变的。
我们可以用ps axj指令查看进程的相关信息,加上管道grep精准找到我们要的进程信息:

这就是我们要找的进程信息,但是我们还不知道每个信息都是什么,因此还可以用head查找进程数据第一行的内容:

可以很明显地看见PID的值是多少。
此时我们发现右边的程序还在运行,如果停止运行,进程的数据是否不一样呢?我们来看看:

我已经停止了程序,对比来看,发现没有./process进程了,因此我们只能看到还在运行的程序的信息。
最后我们来思考一个问题,进程每次重新启动后,其PID还一样吗?答案是否定的,PID相当于一个进程的身份证号,而每次重启进程就要重新随机分发一个身份证号也就是PID,我们来验证一下:

验证结论正确,我们还能观察到,PID也并非完全随机分配,而是逐步递增分配的,本质上是因为你的进程终止之后,后面启动的其他进程就会占用更大的PID,再次重启你的进程后,PID就变大了,当然PID也不会无限增大,是存在上限的,在32位系统中,pid_max一般是32768,而64位系统的pid_max则达到了4194304,约四百万!到顶了之后PID就归零,在0附近重新寻找空闲号码。
为什么不马上使用刚死掉的PID?答案就是安全问题!!!假如一个进程的PID=1234,后来它死了,如果立即把1234分配给新进程,同时外面还有人拿着1234想要kill旧进程,结果误杀新进程,那就炸了,因此内核尽量用新的PID,不着急回收旧的。
好了,本期讲解到此结束,后续仍会继续输出进程相关的内容,再见!