目录
一、前言
二、概念实例,正在执行的程序等
三、描述进程-PCB
四、组织进程
五、查看进程
编辑六、通过系统调用获取进程标示符
七、进程切换和上下文数据
1.进程切换
2.上下文数据
一、前言
在Linux中,每个执行的程序叫做进程,每一个进程都有一个id号。
在window系统中,我们打开任务管理器就能看到,下面都属于一个个进程。
那操作系统该如何管理进程呢?
在我们上篇博客已经写到
先描述,后组织。
- 由操作系统先把进程的结构体描述出来,这个结构体对象叫做进程控制块(PCB,Processing Control Block),里面几乎包含了所有的进程属性信息,并在内部有一个指针指向该进程的代码及数据。
- 在上图的window系统中,我们能看到操作系统能在内存中维护多个进程,在Linux里,当我们把所有进程描述出来后,我们通过双链表将所有进程的PCB组织起来,操作系统只要拿到双链表的头指针就能遍历所有进程了。
- 我们将进程的管理转化成数据结构中PCB的管理,也就是增删查改的过程。
当我们创建一个mytest文件时,在该文件写入数据及代码,该如何去运行呢?在Linux命令行中,我们写入./mytest(为什么是./,这跟环境变量有关系,后面再给大家讲解)。
操作系统会将mytest文件加载到内存中,并在内存中创建该进程,申请PCB。
这就是先描述后组织的过程
总结:
到目前为止我们对进程的理解是:内核PCB数据结构对象(描述这个进程的所有属性值)+自己的代码和数据。
操作系统对这些属性值进程管理:要找到该进程的PCB,根据PCB内的指针找到代码和数据并给CPU进行运算。
二、概念
- 课本概念:程序的一个执行实例,正在执行的程序等
- 内核观点:担当分配系统资源(CPU时间,内存)的实体。
三、描述进程-PCB
- 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。
- 课本上称之为 PCB(process control block),Linux 操作系统下的 PCB 是:task_struct【Linux】Linux 中进程控制块 PCB —— task_struct 结构体结构_linux的进程控制块结构体-CSDN博客
task_struct-PCB的一种
- 为了描述和控制进程的运行,系统中存放进程的管理和控制信息的数据结构称为进程控制块(PCB,Process Control Block),它是进程实体的一部分,是操作系统中最重要的记录性数据结构,它是进程管理和控制的最重要的数据结构。每一个进程均有一个 PCB,在创建进程时,建立 PCB,伴随进程的生命周期,直到进程终止时,PCB 将被删除。
- 在Linux中描述进程的结构体叫做task_struct。
- task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息。
task_struct 有以下进程属性保存在进程控制块中,并随进程的状态而变化:
- 标识符:描述本进程的唯一标示符,用来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级:相对于其他进程的优先级。
假设食堂只有一个窗口,一次只能给一个人打饭,那么我们就需要排队,而排队的本质就是在确立优先级,决定你是先吃饭还是后吃饭,而插队的本质就是在更改优先级。
- 程序计数器:程序中即将被执行的下一条指令的地址。
进程在运行,实际上是 CPU 在执行该进程的代码,那 CPU 如何得知应该取进程中的哪行指令呢?
在 CPU 中有一个寄存器叫做 EIP,这个寄存器通常被称为 PC 指针,保存着当前正在执行指令的下一条指令的地址。
如果某个进程没有跑完,不想运行时,可以把 EIP 中的内容保存进这个进程的 PCB 中,方便后面恢复运行。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
CPU 只认识 PCB,不认识程序代码和数据。可以理解成,通过 PCB 中的内存指针,可以帮我们找到该进程对应的代码和数据。
- 上下文数据:进程执行时处理器的寄存器中的数据。
- I/O 状态信息:包括显示的 I/O 请求,分配给进程的 I/O 设备和被进程使用的文件列表。
- 记账信息:可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
比如:调度一个进程,该进程运行多长时间了,累计被切换多少次了等等。
记账信息是可以指导操作系统去做某些任务的。
举例:假设一个进程被调度了 50s,一个进程被调度了 5s,两个进程优先级一样,那么在下次调度时,应该调度哪个进程呢?
一般是调度时间短的进程。
- 其他信息。
四、组织进程
可以在内核源代码里找到它,所有运行在系统里的进程都以 task_struct 链表的形式存在内核里。
五、查看进程

命令:ps ajx
- a:所有
- j:任务
- x:把所有的信息全部输出
- 一般搭配管道使用,如:ps ajx | head - 1 && ps ajx | grep test,其中 ps ajx | head - l 是把 ps ajx 输出的信息中的第一行信息(属性列)输出。
- 使用 top 命令实时显示进程(process)的动态。
- 通过 /proc 系统文件目录查看。
这个就是bash进程的id
如果要进一步查看 pid 为 29002 的进程信息,查看 /proc/29002 文件目录即可。
操作系统中的 1 号进程是什么呢?
六、通过系统调用获取进程标示符
- 进程id(PID)
- 父进程id(PPID)
运行结果如下:
shell 是命令行解释器(command Interpreter)。
shell 是对所有外壳程序的统称,而 bash 是某一个具体的 shell。bash 也是许多 Linux 发行版的默认 shell。
在执行命令的时候,一般情况下,往往不是由 bash 来解释和执行,而是由 bash 创建子进程,让子进程去执行。
七、进程切换和上下文数据
1.进程切换
- 进程在 CPU 上运行,并不是一直运行到进程结束。每个进程都有一个运行时间单位:时间片。
时间片:从进程开始运行直到被抢占的时间。
比如:进程 1 运行了 50ms,即使进程 1 没有运行完,但它的时间片耗尽了,必须剥离此进程,让出 CPU,切换下一个进程运行。
一般情况下,进程让出 CPU,进行进程切换,有几种情况:
- 来了一个优先级更高的进程。(要求:OS 必须支持抢占)
- 时间片到了。
- 操作系统允许同时运行多个进程。但事实上,一个单核 CPU 永远不可能真正地同时运行多个任务,这些进程 “看起来像” 同时运行的,实则是通过进程快速切换的方式,在一段时间内让所有的进程代码都得到推进,这就是并发。但由于时间片通常很短(在 Linux 上为 5ms-800ms),用户不会感觉到。
多核 CPU / 多个 CPU,允许多个进程同时执行,这就是并行。
大多数操作系统是并发和并行在同时起作用。
2.上下文数据
进程在 CPU 上运行,CPU 寄存器上会产生很多临时数据,当一个进程被切换时,这些数据是需要被保存的,而这些数据被称为进程的上下文数据。
举例:张三大一上完后,家中有事想要休学一年,给学校提出申请,保留学籍一年,这时才能正常离开学校。一年后,张三再次回到学校,给学校提出申请,恢复学籍,这时才能继续正常上学。
上下文数据的保存和恢复:
- 上下文数据的保存:当一个进程在运行中,因为某些原因(比如时间片到了),需要暂时停止运行,让出 CPU,此时进程需要保存好自己所有的临时数据(即当前进程的上下文数据)到对应的 PCB 中,保存的目的是为了恢复。
- 上下文数据的恢复:当这个进程又被切换回来时,或者切换到下一个新进程运行时,只需要把该进程的 PCB 中的上下文数据重新写入到 CPU 寄存器中,即可恢复运行。
进程切换最重要的一步就是上下文的保存和恢复。
运行队列:
- 假如当前操作系统中,有 4 个进程是处于可运行状态的,操作系统会形成一个运行队列。
- 每一个 PCB 用全局的链表连起来,其中可能有若干处于可运行状态的进程,同时也属于运行队列。
- CPU 要执行任务时就从这个运行队列中寻找就行了。
- 当 Linux 内核要寻找一个新的进程在 CPU 上运行时,必须只考虑处于可运行状态的进程(即在 R 状态的进程),因为扫描整个进程链表是相当低效的,所以引入了容纳可运行状态的进程的双向循环链表,也叫运行队列(runqueue)。
- 运行队列容纳了系统中所有可以运行的进程,它是一个双向循环队列。
- 该队列通过 task_struct 结构中的两个指针 run_list 链表来维持。队列的标志有两个:一个是 “空进程” idle_task、一个是队列的长度。
- 操作系统为每个进程状态管理各种类型的队列,与进程相关的 PCB 也存储在相同状态的队列中。如果进程从一种状态转移到另一种状态,则其 PCB 也从相应的队列中断开,并被添加到进行转换的另一个状态队列中。
- 所以 PCB 是可以被列入多种数据结构内的。比如 PCB 在被调度的时候,以及在等待某种资源的时候会被从调度队列移入或移出,包括等待某种资源的等待队列。