前言:章我们将带着大家深入理解 "进程" 的概念,"进程" 这个概念其实使我们一直在接触,只不过这个概念我们没有进行详细讲解罢了,本章我们就把 "进程" 好好地深入理解一番!引出进程的概念后,我们最后再讲解一下 PCB,针对什么是 PCB 以及为什么要有 PCB 等一系列问题进行讲解。
进程的概念(Process)
什么是进程?
进程是一个运行起来的程序。
什么是运行起来的程序呢,跑或没跑?跑起来的程序,和没跑起来的程序?我们不放首先来思考一个问题:
思考:程序是文件吗?
是!文件在磁盘。一开始讲的冯诺依曼,磁盘就是外设,和内存与 CPU 打交道,它们之间有数据交互。你的程序最后要被 CPU 运行,所以要运行起来必须先从磁盘外设加载到内存中。因此,当可执行文件被加载到内存中时,该程序就成为了一个进程。
先描述再组织
思考:操作系统中可能存在多个进程吗?
操作系统里面可能同时存在大量的进程!
既然如此,那操作系统要不要将所以后的进程管理起来呢?
当然要,不要不就乱套了?当前想调用哪个进程,想让哪个进程占用 CPU 资源,
想执行哪个资源,数据一大你不管怎么行?所以我们刚才再次讲解了操作系统管理的概念:
被管理对象的管理本质上是对数据的管理。那么 对进程的管理,本质上就是对进程数据的管理。
所以还是那句话 —— 我们需要 先描述再组织。
所以,当一个程序加载到内存时,操作系统做的不仅仅只是把代码和数据加入到内存,
还要管理进程,创建对应的数据结构。我们讲的是 Linux 操作系统,
Linux 操作系统的内核是 C 语言写的,所以我们管理进程,就要先描述再组织。
进程控制块(PCB)
/* Process Ctrl Block */
struct task_struct {
进程的所有属性数据
};
在操作系统中,我们把描述进程的结构体称为 (Process Ctrl Block) 。
在很多教材中,会把 称为 进程控制块。
想要管理就必须要 "先描述再组织" 。所以每个进程都要有 (task_struct)。
为什么我们的 task_struct 每个进程都要有呢?
因为这是为了管理进程而描述进程所设计的结构体类型,将来当有一个进程加载到内存时,
操作系统在内核中一定要为该进程创建 task_struct 结构体变量,并且要将该变量链入到全局的链表当中。要删掉一个进程,实际上就是遍历所有的链表结点,把对应进程的PCB和代码都释放掉,这就叫对链表做管理。最终你会发现,操作系统对进程的管理,最终变成了对链表的增删查改。
什么是进程?目前为止我们可以总结成:进程 = 可执行程序 + 该进程对应的内核数据结构
系统接口
OS 为什么要给我们提供服务呢?因为计算机和 OS 设计出来就是为了给人提供服务的。
printf or cout 向显示器打印,显示器是硬件
所谓的打印,本质就是将数据写到硬件。
你自己的 C 程序,有资格向硬件写入吗?你是没有资格这么做的。
操作系统不相信任何人的,不会直接暴露自己的任何数据结构,代码逻辑,其他数据相关的细节。
想做系统是通过 系统调用 的方式,对外提供接口服务的。
Linux 操作系统是用C语言写的,这里所谓的 "接口",本质就是C函数。
我们学习系统编程,本质上就是学习这里的系统接口。
进程查看
通过指令查看进程
我们先创建一个 mytest.c 文件,然后写上一个死循环,每隔1秒就打印一句话:
生成 mytest 可执行文件后,使用 ldd 和 file 去查看:
对我们来说,既然它是 executable 那么就是可执行文件,它就是在磁盘上放着。
而我们使用的是云服务器,所以不是在你自己电脑的磁盘上,而是在云服务器的磁盘上放着。
接下来我们 ./mytest 去运行它,此时这个程序就变成了一个进程:
那么此时,在系统中我们可以使用 ps 查看进程:
$ ps aux
$ ps ajx
/* 含义 */
1)ps a 显示现行终端机下的所有程序,包括其他用户的程序。
2)ps -A 显示所有程序。
3)ps c 列出程序时,显示每个程序真正的指令名称,而不包含路径&#