type
status
date
slug
summary
tags
category
icon
password
进程
在我们日常使用电脑或手机的过程中,进程几乎无处不在。打开浏览器是一个进程,启动音乐播放器又是一个进程。虽然我们天天见它们,但未必真的了解它们。如果有人突然问你:进程和线程有什么区别?它们是怎么工作的?你可能会一时语塞。其实,操作系统中的这些概念,在教科书上看起来不复杂,可一旦深入理解就会发现,它们背后蕴含着整个计算机运行机制的关键原理。由于底层机制的原理都是相通的,本文希通过借助python来将抽象概念具体化。
程序和进程
程序:程序是使用计算机语言编写的一组有序指令和数据集合,具备可执行性,通常以文件形式存在于磁盘中,如 .exe、.py、.class 文件等。
进程:进程是程序的一个运行实例。程序是静态的:它本质上是一个代码文件,是计算尚未开始执行的蓝图或“说明书。程序本身不会占用 CPU 或内存资源,它需要被加载并运行,才能变成运行的进程。例如:你电脑上安装的微信、Chrome、IDEA 它们的
.exe 文件就是程序,它们不会主动执行,需要你双击后才会运行。
进程是动态的:表示程序正在运行,且由操作系统管理。每个进程有自己独立的地址空间,拥有自己的内存、打开的文件描述符、系统资源等。操作系统为每个进程分配一个唯一的进程号,称为 PID。为了管理进程,操作系统内核会为每个进程维护一份内核数据结构,用于记录其状态、优先级、调度信息等。并发/并行
多任务编程中的核心概念是
并发 和 并行 ,并发和并行都可以处理多任务,二者的主要区别在于是否同时进行多个的任务。
并发:指两个或多个事件在同一时间间隔内发生(交替执行),时间片的轮转,快速的交替运行任务。这些事件宏观上是同时发生的,但微观上是交替发生的。
并行:指两个或多个事件在同一时刻同时发生。
为了更好的理解并发和并行的概念,我列举了几个例子:
并行:比如在一条跑道上,A和B同时赛跑称为并行,就好比A进程和B进程同时在运行
并发:比如在一条跑道上,A和B都在跑道上,但是是接力赛,就好比A进程和B进程同时都在内存中,但是交替执行,也就是再同一个时刻只能有一个进程在运行。那么为什么不能同时运行呢,因为共享一个cpu,cpu在同一个时间只能为一个进程服务
并发:你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。
并行:你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。
顺序执行:你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。
假设小渣和老渣每人有两个女朋友,在当天需要和一号二号女嘉宾进行约会。小渣采取并行约会:在同一时刻同时进行两个约会任务,而老渣则采取并发约会:在某一时刻进行一个约会任务,交替执行

进程状态
一般说来,一个进程并不是自始至终连续不停地运行,它与并发执行中的其它进程的执行是相互制约的。尽管每个进程是一个独立的实体,有其自己的程序计数器和内部状态,但是各个进程在其生命周期内,会存在相互制约关系及系统的运行环境的变化,使得进程的状态也在不断地发生变化。一般而言,每一个进程至少应处于以下三种基本状态之一。
进程三态 | 说明 |
就绪态 | 进程具备执行条件,等待分配cpu资源,由于其它进程处于运行状态而暂时停止运行 |
运行态 | 进程占有cpu时间片正在运行。单处理器系统中只有一个进程处于运行态,而多处理器系统中有多个进程处于运行态 |
阻塞态(等待态) | 进程暂时停止运行,不具备运行条件,让出cpu |
为了满足进程控制块对数据及操作的完整性要求以及增强管理的灵活性,通常在系统中又为进程引入了两种常见的状态,在三态基础上增加
创建状态和结束状态进程五态 | 说明 |
就绪态 | 进程具备执行条件,等待分配cpu资源 |
运行态 | 进程占有cpu时间片正在运行。单处理器系统中只有一个进程处于运行态,而多处理器系统中有多个进程处于运行态 |
阻塞态(等待态) | 进程暂时停止运行,让出cpu |
创建状态 | 创建一个进程,获取资源的过程。程正在被创建,尚未转到就绪态。进程所需的资源尚不能满足,或系统尚无足够的内存使进程无法装入其中,此时创建工作尚未完成,进程不能被调度运行 |
结束状态 | 进程结束,释放资源的过程。可能是进程正常结束或其他原因中断退出运行。进程需要结束运行时,系统首先必须置该进程为结束态,然后再进一步处理资源释放和回收等工作 |

进程的状态变迁 | 说明 |
NULL → 创建状态 | 一个新进程被创建时的第一个状态 |
创建状态 → 就绪状态 | 当进程被创建完成并初始化后,一切就绪准备运行时,变为就绪状态,这个过程是很快的 |
就绪态 → 运行态 | 处理就绪态的进程被调度后,获得处理器资源,于是进程由就绪态转换为运行态 |
运行态 → 就绪态 | 进程主动放弃CPU:处于运行态的进程在时间片用完后,不得不让出处理器,从而进程由运行态转换为就绪态。<br>抢占:在可剥夺的操作系统中,当有更高优先级的进程就绪时,调度程序将正执行的进程转换为就绪态,让更高优先级的进程执行 |
运行态 → 阻塞态 | 进程请求某一资源的使用和分配或等待某一事件的发生时,如 I/O 操作的完成,它就从运行态转换为阻塞态,主动放弃cpu使用权。进程以系统调用的形式请求操作系统提供服务,这是一种特殊的、由运行用户态程序调用操作系统内核过程的形式 |
阻塞态 → 就绪态 | 进程等待的事件到来时,如 I/O 操作结束或中断结束时,中断处理程序必须把相应进程的状态由阻塞态转换为就绪态 |
运行状态 → 结束状态 | 当进程已经运行完成或出错时,会被操作系统作结束状态处理 |

在许多系统中,进程除了就绪、执行和阻塞三种最基本的状态外,为了系统和用户观察和分析的需要,还引入了一个对进程的重要操作 ——
挂起操作。当该操作作用于某个进程时,该进程将被挂起,意味着此时该进程处于静止状态。如果进程正在执行,它将暂停执行。若原本处于就绪状态,则该进程此时暂不接受调度。与挂起操作对应的操作是激活操作。如果有大量处于阻塞状态的进程,进程可能会占用着物理内存空间,显然不是我们所希望的,毕竟物理内存空间是有限的,被阻塞状态的进程占用着物理内存就一种浪费物理内存的行为。所以,在虚拟内存管理的操作系统中,通常会把阻塞状态的进程的物理内存空间换出到硬盘,等需要再次运行的时候,再从硬盘换入到物理内存。那么,就需要一个新的状态,来描述进程没有占用实际的物理内存空间的情况,这个状态就是挂起状态。这跟阻塞状态是不一样,阻塞状态是等待某个事件的返回。
阻塞挂起状态:进程在外存(硬盘)并等待某个事件的出现;
就绪挂起状态:进程在外存(硬盘),但只要进入内存,即刻立刻运行;
导致进程挂起的原因不只是因为进程所使用的内存空间不在物理内存,还包括如下情况:
用户希望挂起一个程序的执行,比如在 Linux 中用 Ctrl+Z 挂起进程;
通过 sleep 让进程间歇性挂起,其工作原理是设置一个定时器,到期后唤醒进程。
这两种挂起状态加上前面的五种状态,就变成了七种状态变迁(留给我的颜色不多了),见如下图:

进程控制块PCB
在操作系统中,是用进程控制块(process control block,PCB)数据结构来描述进程的,PCB 是进程存在的唯一标识,这意味着一个进程的存在,必然会有一个 PCB,如果进程消失了,那么 PCB 也会随之消失。下面我们执行top命令,让程序在后台运行
当程序启动时,它会被加载到内存中并转化为一个进程,用pidof命令可以查看指定程序名的进程ID
在 Linux 系统中,每个运行的进程都有对应的
/proc 目录,比如进程 ID 为 1571 的进程,就对应 /proc/1571 目录。其中,/proc/[pid]/maps 文件详细展示了该进程的内存映像(虚拟内存空间布局),包括:程序的代码段(text segment);进程使用的全局变量和静态数据段;堆(heap)区域,用于动态分配内存;栈(stack)区域,用于函数调用和局部变量;加载的共享库(动态链接库)映射;其它内存映射文件(如内存映射的文件、设备等)
- 链接:www.qianshuai.cn/article/2487d4cc-a92a-80c5-9b6d-c0afcc04860b
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。







