进程的概念
试想一下这样的场景:我们编写好的代码是怎么运行起来的呢?
我们编写好的代码只是一个存储在硬盘的静态文件,通过编译后就会生成二进制可执行文件,当我们运行这个可执行文件后,它会被装载到内存中,接着 CPU 会执行程序中的每一条指令,那么这个运行中的程序,就被称为「进程」。
那进程的定义就是:进程是程序在某个数据集合上的运行过程,也是操作系统进行资源分配和调度的基本单位。简单来说,进程是程序的一次执行过程,它和程序的区别如下:
- 程序是静态的,它作为系统中的一种资源是永远存在的
- 进程是动态的,它是动态的产生,变化和消亡的,拥有其自己的生命周期
进程不仅包含正在运行的程序实体,并且包括这个运行的程序中占据的所有系统资源,比如说 CPU、内存、网络资源等。
进程的组成
进程主要由三个部分组成:
- 进程控制块 PCB(Process Control Block)
- 数据段
- 程序段
下面我们来一一讲解:
进程控制块 PCB
每个进程有且仅有一个进程控制块,或称进程描述符,它是「进程存在的唯一标识」,是「操作系统用来记录和刻画进程状态及环境信息的数据结构」,也是操作系统掌握进程的唯一资料结构和管理进程的主要依据。所以说 PCB 是提供给操作系统使用的。
简单点说就是操作系统需要对各个进程进行管理,但凡管理时所需要的信息,都会被放在 PCB 中,而且 PCB 是进程存在的唯一标识。创建进程和撤销进程等都是指对 PCB 的操作,当进程被创建时,操作系统为其创建 PCB,当进程结束时,会回收其 PCB。
PCB 主要包含下面的几类信息:
1)进程描述信息:
- 进程标识符 PID :标识各个进程,每个进程都有一个并且唯一的标识符
- 用户标识符 UID :进程归属的用户,用户标识符主要为共享和保护服务
2)进程控制和管理信息:
- 进程当前状态,如 new、ready、running、waiting 或 blocked 等
- 进程优先级:进程抢占 CPU 时的优先级
3)资源分配清单:
- 记录给进程分配了哪些资源。比如分配了多少内存、正在使用哪些 I/O 设备、正在使用哪些文件等
4)CPU 相关信息:
- CPU 中各个寄存器的值,当进程被切换时,CPU 的状态信息都会被保存在相应的 PCB 中,以便进程重新执行时,能从断点处继续执行,就是所谓的保存现场信息。
下面还有两个是数据段和程序段,数据段就是进程运行过程中所需要的数据,程序段就比如我们上面场景中编写的程序,这个简单了解即可。
我们知道了 PCB,那么 PCB 是怎么组织的呢?
主要有这么两种方式:
- 链接方式
- 索引方式
链接方式就是是通过链表的方式进行组织,把具有相同状态的进程链在一起,组成各种队列。比如:
- 将所有处于就绪状态的进程链在一起,称为就绪队列;
- 把所有因等待某事件而处于等待状态的进程链在一起就组成各种阻塞队列;
- 另外,对于运行队列在单核 CPU 系统中则只有一个运行指针了,因为单核 CPU 在某个时间,只能运行一个程序。
就像下图这样:
- 链表的方式:
![就绪队列和阻塞队列](https://i-blog.csdnimg.cn/blog_migrate/321acd54e814f4d3c62e6bc90fc6a94d.png)
- 索引的方式
![就绪队列和阻塞队列](https://i-blog.csdnimg.cn/blog_migrate/bedf540042217bb8153093d507c84959.png)
进程的状态
一个进程并不是一直都是运行着的,它与其他的进程的执行是相互制约的,主要有下面这几种状态:
- 运行状态(Runing):该时刻进程占用 CPU 正在运行
- 就绪状态(Ready):进程具备运行条件,等待系统分配 CPU 以便运行
- 阻塞状态(Blocked):进程不具备运行条件,正在等待某个事件的完成
它们的转换关系如下图所示:
![进程的三种基本状态](https://i-blog.csdnimg.cn/blog_migrate/5f58d18d20cea20b591ccd20ebbff49d.png)
除了上面的三种状态,进程还有下面这几种状态:
- 创建状态(new):进程正在被创建时的状态
- 结束状态(Exit):进程正在从系统中消失时的状态
- 阻塞挂起状态:进程在外存(硬盘)并等待某个事件的出现
- 就绪挂起状态:进程在外存(硬盘),但只要进入内存,即刻立刻运行
加上创建和结束状态,那么进程的五状态图如下:
![进程五种状态的变迁](https://i-blog.csdnimg.cn/blog_migrate/11f0c2245a11494360892c5733ae2080.png)
下面我们详细说说这些状态间的转换:
- NULL -> 创建状态:一个新进程被创建时的第一个状态;
- 创建状态 -> 就绪状态:当进程被创建完成并初始化后,一切就绪准备运行时,变为就绪状态,这个过程是很快的;
- 就绪态 -> 运行状态:处于就绪状态的进程被操作系统的进程调度器选中后,就分配给 CPU 正式运行该进程;
- 运行状态 -> 结束状态:当进程已经运行完成或出错时,会被操作系统作结束状态处理;
- 运行状态 -> 就绪状态:处于运行状态的进程在运行过程中,由于分配给它的运行时间片用完,操作系统会把该进程变为就绪态,接着从就绪态选中另外一个进程运行;
- 运行状态 -> 阻塞状态:当进程请求某个事件且必须等待时,例如请求 I/O 事件;
- 阻塞状态 -> 就绪状态:当进程要等待的事件完成时,它从阻塞状态变到就绪状态;
下面简单的说一下挂起状态:
由于虚拟内存管理原因,进程的所使用的空间可能并没有映射到物理内存,而是在硬盘上,这时进程就会出现挂起状态,另外调用 sleep 也会被挂起。那么状态转换图就变成了下面这样:
![七种状态变迁](https://i-blog.csdnimg.cn/blog_migrate/93cbcb57f67e6ab152587706589e7f97.png)
进程的控制
所谓进程控制就是对系统中的所有进程实施有效的管理,「实现进程状态转换」功能。包括创建进程、阻塞进程、唤醒进程、终止进程等,这些功能均由「原语」来实现,操作系统通过原语来完成进程原理,包括进程的同步和互斥、进程的通信和管理。
这里简单的提一下原语:原语是一种特殊的程序,它的执行具有「原子性」。也就是说,这段程序的运行必须一气呵成,不可中断。
进程的创建
操作系统初始启动时会创建承担系统资源分配和控制管理的一些系统进程,同时还会创建一个所有用户进程的祖先,其他用户进程是在应用程序运行时创建的。
操作系统允许一个进程创建另一个进程,而且允许子进程继承父进程所拥有的资源,当子进程被终止时,其在父进程处继承的资源应当还给父进程。同时,终止父进程时同时也会终止其所有的子进程。
创建进程的过程,也就是「创建原语」包含的内容如下:
- 在进程列表中增加一项,从 PCB 池中申请一个空闲的 PCB(PCB 是有限的,若申请失败则创建失败),为新进程分配一个唯一的进程标识符;
- 为新进程分配地址空间,由进程管理程序确定加载至进程地址空间中的程序;
- 为新进程分配各种资源;
- 初始化 PCB,如进程标识符、CPU 初始状态等;
- 把新进程的状态设置为就绪态,并将其移入就绪队列,等待被调度运行。
主要是下面的一些事件会触发进程的创建:
- 用户登录:分时系统中,用户登录成功,系统会为其建立一个新的进程
- 作业调度:多道批处理系统中,有新的作业放入内存中,会为其建立一个新的进程
- 提供服务:用户向操作系统提出某些请求时,会新建一个进程处理该请求
- 应用请求:由用户进程主动请求创建一个子进程
进程的终止
引起进程终止的事件有三种:
- 正常结束:进程自己请求终止(exit 系统调用)
- 异常结束:比如整数除 0,非法使用特权指令,然后被操作系统强行终止
- 外界干预:Ctrl + Alt + delete 打开进程管理器,用户手动杀死进程
终止(撤销)进程的过程,也就是「撤销原语」包含的内容如下:
- 从 PCB 集合中找到终止进程的 PCB
- 若进程处于运行态,则立即剥夺其 CPU,终止该进程的执行,然后将 CPU 资源分配给其他进程
- 如果其还有子进程,则应将其所有子进程终止
- 将该进程所拥有的全部资源都归还给父进程或操作系统
- 回收 PCB 并将其归还至 PCB 池
进程的阻塞
当进程需要等待某一事件完成时,它可以调用阻塞语句把自己阻塞等待。而一旦被阻塞等待,它只能由另一个进程唤醒。
阻塞进程的过程如下:
- 找到将要被阻塞进程标识号对应的 PCB
- 如果该进程为运行状态,则保护其现场,将其状态转为阻塞状态,停止运行
- 将该 PCB 插入的阻塞队列中去
进程的唤醒
进程由「运行」转变为「阻塞」状态是由于进程必须等待某一事件的完成,所以处于阻塞状态的进程是绝对不可能叫醒自己的。
如果某进程正在等待 I/O 事件,需由别的进程发消息给它,则只有当该进程所期待的事件出现时,才由发现者进程用唤醒语句叫醒它。
唤醒进程的过程如下:
- 在该事件的阻塞队列中找到相应进程的 PCB
- 将其从阻塞队列中移出,并置其状态为就绪状态
- 把该 PCB 插入到就绪队列中,等待调度程序调度
进程的阻塞和唤醒是一对功能相反的语句,如果某个进程调用了阻塞语句,则必有一个与之对应的唤醒语句。
进程上下文切换
所谓进程的上下文切换,就是说各个进程之间是共享 CPU 资源的,不可能一个进程永远占用着 CPU 资源,不同的时候进程之间需要切换,使得不同的进程被分配 CPU 资源,这个过程就是进程的上下文切换,「一个进程切换到另一个进程运行」。
因为进程是由内核进行管理和调度的,所以「进程的上下文切换一定发生在内核态」。
进程上下文的切换也是一个原语操作,称为「切换原语」,其内容如下:
- 首先,将进程 A 的运行环境信息存入 PCB,这个运行环境信息就是进程的上下文(Context)
- 然后,将 PCB 移入相应的进程队列;
- 选择另一个进程 B 进行执行,并更新其 PCB 中的状态为运行态
- 当进程 A 被恢复运行的时候,根据它的 PCB 恢复进程 A 所需的运行环境
引起进程上下文切换的事件,也就是某个占用 CPU 资源运行的当前进程被赶出 CPU 的原因有如下:
- 当前进程的时间片到
- 有更高优先级的进程到达
- 当前进程主动阻塞
- 当前进程终止
好啦,到这里我们的进程的基础知识就讲解完了,记得好好消化哦 😎😎😎
![小风车](https://i-blog.csdnimg.cn/blog_migrate/86a9814e9025db7d70eb247a804673aa.webp?x-image-process=image/format,png)
引用:
https://mp.weixin.qq.com/s?__biz=MzUxODAzNDg4NQ==&mid=2247485175&idx=1&sn=eda03758d4e810afd897ade44c19a508&chksm=f98e425dcef9cb4b3da63e6054f34d5012068b16eb3503d7e5a93bc2a857f1e5116ff793f1d9&scene=178&cur_album_id=1408057986861416450#rd
https://mp.weixin.qq.com/s?__biz=MzI0NDc3ODE5OQ==&mid=2247485461&idx=1&sn=7928f3d9d5a82ad01f902eaf252b00da&scene=19#wechat_redirect