轻松搞定进程原理
目录
进程
进程简介
并发和并行
进程的状态与变迁
进程有五种状态:
- 运行状态:该进程占用CPU
- 就绪状态:可运行,但是由于其他进程正在运行而暂停
- 阻塞状态:该进程正在等待某一事件发生而暂停运行,此时,即使给他CPU控制权,它也无法运行
- 创建状态:进程正在被创建时的状态
- 结束状态:进程正在从系统中消失的状态。
挂起状态:表示进程没有占有物理内存空间。
- 阻塞挂起状态:进程在外存(硬盘)并等待某个事件的出现
- 就绪挂起状态:进程在外存(硬盘),单只要进入内存,就立即运行
线程变迁
- NULL->创建状态:一个新进程被创建时的第一个状态
- 创建状态->就绪状态:当进程被创建完成并初始化后,一切就绪准备运行时,就变为就绪状态,一般来说很快
- 就绪状态->运行状态:处于就绪状态的进程被操作系统的进程调度器选中后,就分配给CPU正式运行改进程
- 运行状态->结束状态:当进程已经完成或出错时,会被操作系统做结束状态处理
- 运行状态->就绪状态:处于运行状态的进程在运行过程中,由于分配给它的运行时间片用完,操作系统会把该进程变为就绪态,接着从就绪态选中另外一个进程运行;
- 运行状态->阻塞状态:当进程请求某个事件且必须等待时,例如请求I/O
- 阻塞状态->就绪状态:当进程要等待的事件完成时,它就从阻塞状态变为就绪状态。
进程的控制结构
在操作系统中,是用进程控制块(PCB)数据结构来描述进程的
PCB是进程存在的唯一表示,这意味着一个进程的存在,必然会有一个PCB,如果进程消失了,那么PCB也会随着消失。
PCB包含的信息
- 进程描述信息
- 进程标识符:表示各个进程,每个进程都有一个并且唯一的标识符
- 用于标识符:进程归属的用户,用户标识符主要为共享和保护服务
- 进程控制和管理信息
- 进程当前的状态,如:new、ready、running、waiting或blocked
- 进程优先级:进程抢占CPU时的优先级
- 资源分配清单
- 有关内存地址空间或虚拟地址空间的信息,所打开文件的列表和所使用的I/O设备信息
- CPU相关信息
- CPU中各个寄存器的值,当进程被切换时,CPU的状态信息都会被保存在相应的PCB中,以便进程重新执行时,能从断点处继续执行。
PCB如何组织
通常是通过链表的方式进行组织,把具有相同状态的进程链在一起,组成各种队列,比如:
- 将所有处于就绪状态的进程链在一起,称为就绪队列
- 把所有因等待某事件而处于等待状态的进程链在一起组成各种阻塞队列
- 另外,对于运行队列在单核CPU系统中则只有一个运行指针了,因为单核CPU在某个时间只能运行一个程序。
就绪队列和阻塞队列链表的组织形式如下所示:
另外除了链接的组织方式,还有索引方式,它的工作原理:将同一状态的进程组织在一个索引表中,索引表项指向响应的PCB,不同状态对应不同的索引表。
一般来说会选择链表,因为可能面临创建、销毁等调度导致进程状态发生变化,所以链表能更加灵活的插入和删除
进程的控制
当我们熟悉了进程的状态变迁和进程的数据结构PCB后,再来看看进程的创建、终止、阻塞、唤醒的过程,这些过程也就是进程的控制
创建进程
操作系统运行一个进程创建另一个进程,而且运行子进程继承父进程所拥有的资源,当子进程被终止时,其父进程处继承的资源应当还给父进程。同时终止父进程时也同时会终止所有的子进程
创建进程的过程:
- 为新进程分配一个唯一的进程标识号,并申请一个空白的PCB,PCB是有限的,若申请失败则创建失败
- 为进程分配资源,此处如果资源不足,进程就会进入等待状态,以等待资源
- 初始化PCB
- 如果进程的调度队列能够接纳新进程,那就将进程插入到就绪队列,等待被调度运行
终止进程
进程终止的方式有三种:正常结束、异常结束和外键干预(直接kill掉)
终止进程的过程如下:
- 查找需要终止的进程的PCB
- 如果处于执行状态,则立即终止改进程的执行,然后将CPU资源分配给其他进程
- 如果其还有子进程,则该将所有子进程终止
- 将该进程所拥有的全部资源都归还给父进程或操作系统
- 将其从PCB所在队列中删除
阻塞进程
当进程需要等待某一事件完成时,它可以调用阻塞语句把自己阻塞等待。一旦被阻塞等待,它就只能由另一进程唤醒
阻塞进程的过程:
- 找到将要被阻塞进程标识号对应的 PCB;
- 如果该进程为运行状态,则保护其现场,将其状态转为阻塞状态,停止运行;
- 将该 PCB 插入的阻塞队列中去;
唤醒进程
进程由运行转变为阻塞状态是由于进程必须等待某一事件的完成,所以出于阻塞状态的进程是绝对不可能叫醒自己的。
如果某进程正在等待 I/O 事件,需由别的进程发消息给它,则只有当该进程所期待的事件出现时,才由发现者进程用唤醒语句叫醒它。
唤醒进程的过程如下:
- 在该事件的阻塞队列中找到相应进程的 PCB;
- 将其从阻塞队列中移出,并置其状态为就绪状态;
- 把该 PCB 插入到就绪队列中,等待调度程序调度;
进程的阻塞和唤醒时一对功能相反的语句,如果某个进程调用了阻塞语句,则必有一个与之对应的唤醒语句。
进程的上下文切换
各个进程之间是共享CPU资源的,在不同的时候进程之间需要切换,让不同的进程可以在CPU执行,那么一个进程切换到另一个进程运行,称为进程的上下文切换。
CPU上下文切换
由于任务是交给CPU运行的,那么在每个任务运行前,CPU需要知道任务从哪里加载,又从哪里开始运行
所以,操作系统需要事先帮CPU设置好CPU寄存器和程序计数器。(CPU上下文)
- CPU寄存器是CPU中一个容量小,速度快的内存
- 程序计数器:则是用来存储CPU正在执行的指令位置、或者即将执行的下一条指令位置。
CPU 上下文切换就是先把前一个任务的 CPU 上下文(CPU 寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。
任务主要包括进程、线程和中断。所以,可以根据任务的不同,把CPU上下文切换分为:进程上下文切换、线程上下文切换和中断上下文切换
进程的上下文切换
进程是由内核管理和调度的,所以进程的切换只能发生在内核态,所以进程的上下文切换不仅包含了虚拟内存、栈、全量变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的资源。
通常,会把交换的信息保存在进程的 PCB,当要运行另外一个进程的时候,我们需要从这个进程的 PCB 取出上下文,然后恢复到 CPU 中,这使得这个进程可以继续执行,如下图所示:
发生进程上下文切换的场景
- 为了保证所有进程可以得到公平调度,CPU 时间被划分为一段段的时间片,这些时间片再被轮流分配给各个进程。这样,当某个进程的时间片耗尽了,就会被系统挂起,切换到其它正在等待 CPU 的进程运行;
- 进程在系统资源不足(比如内存不足)时,要等到资源满足后才可以运行,这个时候进程也会被挂起,并由系统调度其他进程运行;
- 当进程通过睡眠函数 sleep 这样的方法将自己主动挂起时,自然也会重新调度;
- 当有优先级更高的进程运行时,为了保证高优先级进程的运行,当前进程会被挂起,由高优先级进程来运行;
- 发生硬件中断时,CPU 上的进程会被中断挂起,转而执行内核中的中断服务程序;
进程间通信
进程调度算法
线程
最后
- 如果觉得看完有收获,希望能给我点个赞,这将会是我更新的最大动力,感谢各位的支持
- 欢迎各位关注我的公众号【java冢狐】,专注于java和计算机基础知识,保证让你看完有所收获,不信你打我
- 如果看完有不同的意见或者建议,欢迎多多评论一起交流。感谢各位的支持以及厚爱。