一、引入
操作系统管理软硬件的本质: 先描述,再组织“
当我们理解了这个本质,就很容易理解操作系统如何管理进程,以及为什么要这样管理进程。
1、何为 ”先描述,再组织“ ?
操作系统的作用:
1、操作系统对下软硬件资源的管理,稳定的,高效的,安全的,能进行良好的工作(手段)
2、操作系统对上要给用户提供一个稳定的,高效的,安全的运行环境(目的)
在整个计算机软硬件架构中,操作系统的定位是:一款纯正的“搞管理”的软件
2、如何理解 “管理”
管理的本质:先描述被管理对象,再组织被管理对象
2.1 管理的例子:学生与学校
我们将这个概念具体化到学校对学生管理的例子中:
(1)描述阶段:建立学生档案
当一名新生入学后,学校会为其创建一份档案,这份档案包含了学生的个人信息,如姓名、性别、出生日期、家庭住址、联系方式等。这些信息构成了对该学生的完整描述,使得管理者能够通过查阅档案了解该学生的基本情况。
(2)组织阶段:通过信息进行管理
有了学生档案后,学校可以根据不同的需求对这些档案进行分类、归档,从而实现对学生的有效管理。例如:
- 按年级和班级组织:学校可以根据学生的年级和班级,将学生档案进行分类存放,方便进行教学资源的调配和学籍管理。
- 按成绩或表现组织:学校还可以根据学生的学术成绩或在校表现,对学生档案进行排序,便于跟踪学生成长轨迹,及时发现问题并采取相应措施。
这种管理方法的核心在于先准确地描述每个被管理对象(即学生),然后基于这些描述信息进行有效的组织,从而实现高效有序的管理。
2.2 操作系统管理进程
在操作系统中,管理进程也是遵循“先描述,再组织”的原则:
(1)先描述:创建进程控制块(PCB)
当一个新的进程被创建时,操作系统会在内存中为其分配一个数据结构,这个数据结构被称为进程控制块(Process Control Block, PCB)。PCB 包含了操作系统管理进程所需的所有信息,如进程标识符、状态信息、CPU 上下文、内存管理信息、调度信息等等。这个过程类似于学校为新入学的学生创建个人档案,其中包含了该学生的所有相关信息。
(2)再组织:将 PCB 链接到队列中
操作系统创建了 PCB 后,会将这个 PCB 作为一个节点链接到相应的队列中。这些队列可以是:
- 就绪队列:保存所有准备好等待 CPU 时间的进程的 PCB。
- 阻塞队列:保存那些因等待某些事件(如 I/O 完成)而暂时不能运行的进程的 PCB。
- 运行队列:保存当前正在 CPU 上执行的进程的 PCB(一般情况下只有一个)。
通过这种方式,操作系统可以轻松地找到处于不同状态的进程,并且在需要的时候能够快速地切换进程的执行状态。例如,当一个进程从就绪状态变为运行状态时,操作系统只需要将该进程的 PCB 从就绪队列移动到运行队列即可。
这种管理方式不仅简化了操作系统对进程的管理,还提高了系统的效率,因为它避免了频繁地搜索整个内存来查找特定进程的需要。此外,通过合理地组织这些队列,操作系统可以更好地实现进程调度策略,如轮转法、优先级调度等,从而优化系统的整体性能。
二、进程
1、进程的概念
课本概念:一个正在执行的程序就是一个进程(这一句是正确的废话,不完全正确)。
内核观点:担当分配系统资源(CPU时间,内存)的实体。
一个真正的进程是由:该进程的PCB 和 该进程的代码数据 所组成,而绝不是仅仅指一个运行起来的程序.
2、描述进程:PCB
PCB 的概念:进程所有信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合,通常称之为 PCB (process control block)。
PCB 是进程控制块的统称,而 task_struct 则 Linux 内核中具体的 PCB 实现。
就像 shell 是命令行解释器的统称,bash 是 Linux 系统中 shell 的一种具体实现版本。
PCB 的主要作用是保存和记录进程的状态信息,以便操作系统能够在多任务环境下正确地切换上下文并恢复进程的执行。当一个进程被创建时,操作系统会为这个进程分配一个 PCB ;当进程终止或退出时,PCB 也会被销毁。
PCB 是形成一个进程的基础:需要执行某个程序时,系统先创建一个 task_struct (即进程 PCB)并记录该进程所需的相关信息数据,并将该数据结构存储在内存中,再将该程序的可执行文件加载到内存中,这样就完整的创建了一个进程。
因此,并不说一个程序被加载到内存中就代表形成了一个进程,而是需要生成对应的存储该进程的各种信息的 task_struct ,并交给操作系统同一管理,这样的进程才是真正被操作系统认可的进程。
task_struct 内容分类
task_struct 包含了操作系统的内核用来管理和控制进程所需要的一切信息。这些信息可能包括但不限于以下几项:
- 进程标识符(
PID):用来唯一标识一个进程。 - 进程状态:比如运行(
Running)、阻塞(Blocked)等(在 Linux 系统中,则有更加详细的进程七大状态) - 上下文:
CPU 寄存器的值,例如程序计数器(PC)、状态寄存器和其他机器状态。 - 进程地址空间和页表:用于管理进程的内存空间。
- 进程调度信息:优先级(
PRI)、时间片等,用于调度算法。 - 运行时间(
TIME):进程已经使用了多少 CPU 时间。 I/O 状态:进程是否正在等待 I/O 操作完成。- 其他信息
看到这么多陌生的进程属性不要慌,后面我们会一一解释 task_struct 中的各项属性的作用
(注:我们本篇文章会选几个重要的进程属性讲解)
3、组织进程
操作系统将内存中的所有 task_struct 作为链表节点链接到一个链表数据结构中,因此操作系统对进程的管理工作就变成了对该链表数据结构的增删查改工作。
操作系统管理直接管理的并不是某个进行程序本身,而是该程序的属性信息即 PCB(就像学校管理学生并不会直接管理学生这个人,而是管理学生的档案信息)
运行起来的程序:表示 OS 调度器根据该进程的 task_struct 属性,,对该进程调度运行
进程被CPU运行有先后顺序:表示进程的 task_struct 被链入 CPU 的队列中排队
4、简单理解一下进程PCB的作用与PCB如何被组织:面试官的例子
找工作写的简历,就是包含着你个人的各种属性,相当于你的 task_struct
面试官就像进程调度器,面试官选择简历的过程,就是进程调度器通过进程的 task_struct 调度进程给CPU运行的过程。
面试官打电话来找你,就是通过指针找到你这个进程。
面试官面试你的过程,就是执行你这条程序。
面试官根据简历的好坏选择好简历来优先选择面试者,就是进程调度器根据进程优先级进行调度进程
一面通过了,一面的面试官将你的简历扔了,然后你进入二面,二面的面试官会再次获取你的简历,这个过程呈现动态的过程,一份简历被查看又被丢弃又被查看,就是一条程序被CPU调度又停止调度而后又被调度,即为动态调度的过程。
5、查看进程
5.1 进程的信息可以通过系统文件夹 /proc 查看
命令:ls /proc
这些数字就是该进程的 进程标识符(即 PID),用来唯一标识一个进程(相当于进程的身份证号)
命令:ls /proc/1
5.2 进程的状态信息可以通过两个命令查看
(1)命令: ps axj
可以查询到当前系统下,运行的所有进程的状态信息
我们这里写一个死循环程序,也可以通过 ps 命令找到
首先,创建并允许一个死循环程序
其次,另开一个 shell 命令行窗口
通过命令 ps axj | head -1; ps axj | grep test, 就能找到正在运行的 test 进程,即 PID=106286 的进程
(2)命令:top
top 命令是 Linux 中一个非常强大的实时系统监视工具,它可以显示系统中各个进程的动态信息。
如下动图,我们可以发现各项信息正在动态变化刷新,每隔 2秒多 刷新一次
而第一条正是我们一直在运行的死循环进程test
6、进程属性
6.1 进程属性:进程标示符 PID/ PPID
(1)进程标示符的概念
PID (Process Identifier):进程 id
PPID(Parent Process Identifier):父进程 id
(2)获取进程标示符的函数
1、获取当前进程自己的 pid : getpid()
2、获取当前进程父进程的 pid , 即 ppid :getppid()
需要的头文件 <unistd.h>
(3)使用示例
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("pid: %d\n", getpid());
printf("ppid: %d\n", getppid());
// 放置一个死循环,阻塞该进程,不让改进程结束,方便我们查看该进程信息
while(1){};
return 0;
}
运行该代码,同时使用命令 ps axj | head -1; ps axj | grep test 查看该进程状态信息
证明了这两个函数的作用
6.2 进程属性:进程状态 STAT
Linux 有七大进程状态:运行状态 R、休眠状态 S、磁盘休眠状态 D、暂停状态 T、追踪暂停状态 t、死亡状态 X、僵尸状态 Z
这些状态的概念和用途,可以看这篇博客,里面有详细介绍:
6.3 进程属性:运行时间 TIME
命令:top
top 命令显示的进程属性中的 TIME 或 TIME+ 列通常表示的是该进程自启动以来所累积的 CPU 时间(以秒为单位),也就是该进程运行了多久
查看我们刚刚运行的死循环程序 test,可以看到它 运行了 8min 45s
6.4 进程属性:优先级 PRI
进程优先级的不同,往往决定着该进程被调度进CPU中运行的先后顺序,优先级越高,就越先被调度到CPU中运行,即先一步占有 CPU 资源。
本知识可以跳转这篇博客,可以得到更加详细的回答:
6.5 进程属性:上下文
进程的上下文和进程的切换操作密切相关,两者需同时了解
本知识可以跳转这篇博客,可以得到更加详细的回答:
6.6 进程属性:用户标识符 UID
每个进程都有一个与之关联的用户ID,用于标识该进程属于哪个用户账户。
UID:即 user id
UID在Linux系统中有以下几个重要特性:
6.6.1 UID 的作用
(1)在Linux中,UID用于确定进程的权限和能力:
- 文件的读写执行权限检查是基于进程的有效
UID 来进行的。 - 只有
root 用户(UID 为0)拥有系统的全部权限,包括修改系统配置文件、停止其他服务等。 - 普通用户拥有的权限受限于他们的
UID 。
当一个进程试图访问系统资源或执行某些操作时,内核会检查该进程的 UID 来确定是否有足够的权限来执行相应的操作。
(3)和直接查找比较用户的字符串名,比较 UID 显然是更加高效的
6.6.2 图示
进程 proc 是在普通用户 mine 中启动的,该进程 UID 为 1001
进程 test 是在超级用户 root 中启动的,该进程 UID 为 0
6.7 进程属性:进程地址空间
本知识可以跳转这篇博客,可以得到更加详细的回答: