前言:本篇讲解Linux进程概念相关内容。 操作系统被称为计算机世界的哲学, 可以见得操作系统的知识并不好理解。 对于这篇进程概念的讲解, 博主认为, 如果没有一些前置知识的话,里面的有些概念并不好理解。 但是如果学习了冯诺依曼体系结构, 再了解了操作系统是如何对硬件进程管理之后, 进程就变得会好理解很多。
ps:本篇内容适合学过一些数据结构的友友门进行观看, 但是可能有些概念理解不了, 最好了解一些冯诺依曼体系结构和操作系统对硬件的管理再来学习本节。 对于这两个知识块, 博主已有文章:
linux_进程周边知识——理解冯诺依曼体系结构-****博客
linux进程周边知识——内核对硬件的管理——计算机世界的管理-****博客
目录
进程的定义
linux下的进程
理解linux下的进程
操作系统对进程的管理 (先描述, 再组织)
PCB
进程的定义
已经加载到内存的程序, 就叫做进程。 有些教科书上面叫做任务。
linux下的进程
下面是windows下面的进程:
linux下面的进程, 我们要查看怎么查看呢? ——需要输入ps指令, 如下图:
ps axj就能查看当前机器下所有的进程。但是也有另一个指令能够查看进程, 这个进程是top
现在, 我在这里创建一个程序:
我现在将这个程序跑出来:
然后打开进程管理, 查看当前的进程:
也有的教材中称正在运行的程序叫做进程。
其实正在运行的程序本质上就是cpu正在对该程序进行计算, 而想要让cpu计算一个程序, 那么首先这个程序就要被加载到内存中。 所以正在运行的程序本质上也是被加载到内存中的程序。 同样是进程。
那么思考另一个问题, 对于操作系统来说, 他是一个软件。 一个做软硬件管理的软件, 那么他管理这些硬件的时候, 一定是运行着的, 也就是说, 操作系统也是一个进程。 其实, 本质上, 我们在电脑开机的时候, 其实就是在将操作系统从磁盘缓存到内存中, 让其成为一个进程。
理解linux下的进程
如何理解上面的概念呢?
上面是一个简化的冯诺依曼, 现在, 假如有一个程序需要需要运行, 这个程序就要从磁盘加载到内存中, 一个程序, 归根结底就是数据和代码构成的。 而这些的本质都是代码。
而且一个操作系统之中, 不仅仅只有一个进程, 他有很多进程。 比如说我们一边听歌一遍聊, 或者一遍打游戏, 一边听歌, 一边聊天。
这都是多进程的体现, 更不用说还有许多后台进程, 这些进程我们看不到, 但他们确确实实存在。
然后, 既然进程多了, 那么操作系统为了这些进程能够在系统内合理的运行, 就要对他们进行管理, 那么如何管理呢? 就是和操作系统管理硬件的思路是一样的——事实上, 计算机世界的管理甚至是现实中的管理都是这样的, 也就是——先描述, 再组织。
任何一个进程, 在加载到内存的时候, 形成真正的进程时, 都要现在内存中开一个进程(属性)的结构体对象, 简称PCB。 全程process cral block —— 进程控制块。
这里我们可以思考一个问题, 那就是人是如何辨认一个事物或者对象的? 我们在和别人描述一个人时, 是不是像那个人描述一个人的身高, 体重, 外表是白是黑? 等等。 这些描述的, 其实就是属性。 当我们进行描述的属性够多。 那么是不是就越能指向一个人? 所以, 当特征足够多的时候, 这些属性的集合, 那么就能指向一个人。 所以, 对于上面的PCB来说, 它就是一个进程属性的集合。
那么我们知道, 对于操作系统来说, 它是用c语言写的。 所以形成的结构体对象, 就一定是结构体。 那么这里要提三个概念:
进程编号: 我们知道, 对于一个学校的学生来说, 每一个学生都有一个学号, 目的就是为了区分每一个学生。 那么对于进程也是一样, 每一个进程都有自己的编号, 这个就叫做进程编号。
进程的状态: 每一个进程都有自己的状态, 有的进程可能在运行, 有的进程可能在休眠。 所以, 就需要进程的状态进行标识。
进程的优先级: 进程需要被cpu运行, 调度, 那么势必就需要一个东西——优先级。
未来当进程加载到内存中时, 操作系统就要为进程创建相应的PCB对象。 那么就是说只要进程加载到内存中, 那么操作系统中就有一根这个进程的代码, 一份保存这个进程属性的PCB代码块。
对于PCB来说, 我们可以这么理解: 就像我们升学一样, 我们升学, 就要将我们的学籍档案进入即将升入的学校, 然后我们的人再到学校进行报道。 这个时候, 我们才是这个学校的学生。 如果我们只有人进入到了学校。 那么我们不算这个学校的学生, 就比如保安大爷, 虽然人在学校, 但是它们不算是学校的学生。 如果我们只有学籍档案到了学校, 但是人没有到学校。 就比如开学的当天, 我们这个时候还没有到学校报道, 但是学籍档案还在学校。 我们就不是这个学校的学生。 而这里的PCB就相当于学籍档案, 这里的data就相当于我们自己。
现在看下面这个图:
这里的PCB是由操作系统自己生成并且维护的。 代码和数据是程序加载到内存中的。 那么既然我们的程序加载到内存, 操作系统同时会自动创建一个PCB, 那么就是说, 这里的数据代码和PCB合起来, 才能叫做进程。
所以, 这里就可以按照我们自己的理给一个进程的定义: 进程 = 内核创建的PCB对象(用来描述程序也就是代码的属性值) + 你自己写的代码和数据。
操作系统对进程的管理 (先描述, 再组织)
操作系统管理进程的时候, 看的是PCB对象而不是我们的代码和数据。 在操作系统中, 对于一个进程来说,PCB里面有一个指针指向自己的代码和数据。 如下图:
对于多个进程来说, 这些进程不是随意分散在内存中的, 而是由某个或者多个数据结构保存起来的。 最简单的就是双链表数据结构, 如下图为链接的简单图:(就是每个PCB都有一个指向自己的代码和数据的指针, 用来找到代码代码本体。 还有一个后指针指向下一个进程, 一个前指针指向前一个进程, 注意: 这里的前指针没有画, 但不代表没有。)
这样, 操作系统对于进程的管理就转化为了对于双链表的数据结构的管理。
其实对于这种PCB和数据代码分开, 只管理PCB的管理模式, 在生活中很常见。 就比如我们在竞争部门委员的时候。 我们给学校的部门投递自己的简历。面试我们的这些学长, 他们在面试我们的时候是让我们在屋外排队等待面试吗? 不是的, 他们是让我们在一个静候室里面, 按照简历的顺序, 给我们安排面试的顺序。 而这里的简历,不就是操作系统中的PCB? 这里的我们本人, 不就是加载到内存中的程序?——这上面的过程, 本质上就是一个先描述, 再组织。
PCB
linux下的PCB叫做task_struct
- task_struct里面封装了很多东西, 他包含了进程内部的所有属性, 所以非常大。 我们知道, 在c/c++语言中, struct 结构体内部其实就是封装一个事物的所有属性, 这些属性, 其实描述的就是对象, 这就是面向对象, 所以task_struct描述的就是进程。
那么, task_struct里面到底有什么东西呢?
- 标识符:也叫做PID, 这个是用来区别其他的进程。
- 状态: 用来记录当前进程的状态, 进程可以是运行中, 可以是休眠中, 可以是暂停中等等。
- 优先级:进程要被cpu调度, 但是cpu就那么点空间, 而进程那么多, 所以这些进程是要竞争的。 为什么这个进程这个时候要被运行。 而其他进程不运行呢? 这就是优先级。
- 程序计数器:当前运行程序的下一条指令的地址——这里不好理解, 回想一下我们学习的函数栈帧, 程序在调用函数时, 是不是会先将这个函数处的下一条指令的地址保存下来? 这个其实就是类似于程序计数器。程序计数器是cpu里面的一个寄存器, 它专门保存当前指令的下一条指令。
- 内存指针:PCB找到自己的代码和数据。
- 上下文数据和IO状态信息: 这两个博主知识储备不足,本篇文章也不会涉及, 有兴趣的友友可以自己学习
- 记账信息:记录程序运行的时间等等。 可以衡量调度器的优劣。
再次强调:
在进程当中, 我们管理进程, 其实是对PCB进行管理。
那么, 在linux中, 内核是如何组织进程的呢? 在linux内核中, 最基本的组织进程task_struct的方式, 是采用双向链表进行组织的。
但是, 要注意, pcb不仅仅属于一个双链表, 在操作系统中, pcb内部可能不仅仅只有一个链表指针, 也有可能有队列的指针之类。 意思就是说, pcb不仅仅可能只被链在在了一个链表里, 同时pcb也可能被链在了一个队列里。或者放在其他的一个数据结构当中。
那么利用上面的特性PCB就可以拥有不同的状态, 比如PCB此时正在运行, 那么就把他链入运行队列当中, 比如PCB正在等待, 就把他链入等待队列当中, 比如PCB正在休眠, 就把他链入休眠队列当中。
所以, 进程如何工作, 取决于我们被他放到了哪个数据结构当中。
现在我们来看另一个问题, 下午是正在跑的两个程序, 左边是查看当前正在跑的右边的两个程序:
之所以会有第三个是因为指令也算是一个进程, 但是因为很快, 一般我们查不到, 但是对于过滤来说, 过滤的后面也有process, 所以在cpu进行调度的时候, 就要将grep也给带上。
这里最重要的是前面的那几个数字。这个东西叫做PID, 也叫做进程的标识符, 虽然我们运行的两个程序, 都是process-7-11.exe, 但是对于操作系统来说, 这是两个程序, 那么他就会生成两份PCB对象。 所以, 内核看的不是有几分代码,而是有几个进程!!
另一个知识点是proc: 可以查看当前系统中运行的进程。 我们可以使用 -l 查看细节。
然后我们就会发现, 这些进程都是目录, 并且这些目录的名字都是数字。
既然进程都可以在proc目录下以文件的形式显示, 那么我们就可以查看我们当前的process-7-11.exe进程:
现在我们来看上面的绿色字段, 这个绿色字段前面是exe, 后面是一个路径, 这个路径其实就是process-7-11.exe的文件位置。 对于上面的蓝色字段, 这个蓝色字段其实就是运行的程序所在的工作目录, 现在我们来思考一个问题。 为什么对于一个touch指令, mkdir指令这些来说, 创建的文件都在当前目录下。 答案就是进程中的这个cwd文件。 这个文件默认保存了当前进程的运行路径, 那么在使用路径的时候, 就会在当前路径创建文件了。
--------------------------------以上, 就是本节的全部内容。下面是博主的笔记: