操作系统02
什么是进程?
进程就是程序的一次执行过程,它是动态的产生,变化,消亡的有生命周期的;并且进程还包括运行中占用的系统空间、CPU等;
为了防止一个进程中两个线程同时使用一个内存区域的简单办法就是门口加一把锁。先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去。这就叫”互斥锁”(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域。
某些内存区域,只能供给固定数目的线程使用时,就是在门口挂 n 把钥匙。进去的人就取一把钥匙,出来时再把钥匙挂回原处。后到的人发现钥匙架空了,就知道必须在门口排队等着了。这种做法叫做 “信号量”(Semaphore),用来保证多个线程不会互相冲突。
进程的组成
PCB :是提供给操作系统用的,是进程存在的标志,一般包含4个内容:
1)进程描述信息:用来让操作系统区分各个进程
- 当进程被创建时,操作系统会为该进程分配一个唯一的、不重复的 “身份证号”— PID(ProcessID,进程 ID)
- 另外,进程描述信息还包含进程所属的用户 ID(UID)
2)进程控制和管理信息:记录进程的运行情况。比如 CPU 的使用时间、磁盘使用情况、网络流量使用情况等。
3)资源分配清单:记录给进程分配了哪些资源。比如分配了多少内存、正在使用哪些 I/O 设备、正在使用哪些文件等。
4)CPU 相关信息:进程在让出 CPU 时,必须保存该进程在 CPU 中的各种信息,比如各种寄存器的值。用于实现进程切换,确保这个进程再次运行的时候恢复 CPU 现场,从断点处继续执行。这就是所谓的保存现场信息。
程序段:程序的代码生成的指令序列
数据段:进程运行中的各种数据(比如定义的变量)
程序段、数据段是给进程自己用的,PCB给操作系统用的。
进程的状态
经典的进程三态模型如下:
- 运行态(running):进程占有 CPU 正在运行。
- 就绪态(ready):进程具备运行条件,等待系统分配 CPU 以便运行。
- 阻塞态 / 等待态(wait):进程不具备运行条件,正在等待某个事件的完成。
上图中的时间片用完,可以这样理解:
进程是并发执行的嘛,宏观上在一段时间内能同时运行多个程序,但其实微观上是交替发生的。也就是说 CPU 一般不会让一个进程一次性执行完,为了保证所有进程可以得到公平调度,CPU 时间被划分为一段段的时间片,这些时间片再被轮流分配给各个进程。某个进程的时间片用完后这个进程就会进入就绪态,而其他被分配到时间片的进程就会进入运行态。这个处于就绪态的进程就需要等待进程调度程序的下一次调度,为其分配 CPU 时间片后才能再次恢复运行。
需要注意的是:阻塞态是由于缺少需要的资源从而由运行态转换而来,但是该资源不包括 CPU 时间片,缺少 CPU 时间片会从运行态转换为就绪态。
很多系统中都增加了新建态(new)和终止态(exit),形成五态模型:
- 新建态(new):进程正在被创建时的状态
- 终止态(exit):进程正在从系统中消失时的状态
从上图可以发现,只有就绪态和运行态可以相互转换,其它的都是单向转换。
这些不同状态的进程操作系统是如何进行管理的呢?上文说过,PCB 是提供给操作系统使用的,是操作系统管理进程的主要依据。没错,操作就是通过 PCB 来管理这些拥有不同状态的进程的。
进程的 PCB 会通过某种方式组织起来,一般来说,操作系统会把处于同一状态的所有进程的 PCB 链接在一起,这种数据结构就称为进程队列(Process Queue)。
进程控制
原语是操作系统内核中一段特殊的程序,它具有原子性(该程序运行必须一次运行,不可中断)
操作系统通过原语实现进程状态的转化,也就是进程的创建、终止、阻塞、唤醒;
进程的创建过程:
- 在进程列表中增加一项,从 PCB 池中申请一个空闲的 PCB(PCB 是有限的,若申请失败则创建失败),为新进程分配一个唯一的进程标识符;
- 为新进程分配地址空间,由进程管理程序确定加载至进程地址空间中的程序;
- 为新进程分配各种资源;
- 初始化 PCB,如进程标识符、CPU 初始状态等;
- 把新进程的状态设置为就绪态,并将其移入就绪队列,等待被调度运行。
进程的上下文切换
各个进程之间共享内存资源,当进程切换时不同进程分配不同的内存空间这就是进程的上下文切换。也就是一个进程切换到另一个进程,
进程的切换一定发生在内核态中
进程切换也就是切换原语的流程:
- 首先,将进程 A 的运行环境信息存入 PCB,这个运行环境信息就是进程的上下文(Context)
- 然后,将 PCB 移入相应的进程队列;
- 选择另一个进程 B 进行执行,并更新其 PCB 中的状态为运行态
- 当进程 A 被恢复运行的时候,根据它的 PCB 恢复进程 A 所需的运行环境
线程的优缺点
线程的特征和进程差不多,进程有的他基本都有,比如:
- 线程具有就绪、阻塞、运行三种基本状态,同样具有状态之间的转换关系;
- 线程间可以并发执行
- 在多 CPU 环境下,各个线程也可以分派到不同的 CPU 上并行执行
线程的优点:
一个进程中可以同时存在多个线程,这些线程共享该进程的资源。进程间的通信必须请求操作系统服务(因为 CPU 要切换到内核态),开销很大。而同进程下的线程间通信,无需操作系统干预,开销更小。
不过,需要注意的是:从属于不同进程的线程间通信,也必须请求操作系统服务。
线程间的并发比进程的开销更小,系统并发性提升。
同样,需要注意的是:从属于不同进程的线程间切换,它是会导致进程切换的,所以开销也大。
线程的缺点:
- 当进程中的一个线程奔溃时,会导致其所属进程的所有线程奔溃。
举个例子,对于游戏的用户设计,就不应该使用多线程的方式,否则一个用户挂了,会影响其他同个进程的线程
进程调度
进程调度,就是从进程的就绪队列(阻塞)中按照一定的算法选择一个进程并将 CPU 分配给它运行,以实现进程的并发执行。
非抢占式调度算法
非抢占式的意思就是,当进程正在运行时,它就会一直运行,直到该进程完成或发生某个事件发生而被阻塞时,才会把 CPU 让给其他进程。
- 先到先服务FCFS
先到的进程就先被调度
- 最短作业优先SJF
当前已到达的进程中运行时间最短的先调用
- 高响应比优先HRRN
只有当前运行的进程主动放弃 CPU 时(正常/异常完成,或主动阻塞),才需要进行调度,调度时计算所有就绪进程的响应比,为响应比最高的进程分配 CPU。
响应比 = (进程的等待时间 + 进程需要的运行时间) / 进程需要的运行时间
抢占式调度算法
抢占式的意思就是,当进程正在运行的时,可以被打断,把 CPU 让给其他进程。
- 最短剩余时间优先
当一个新的进程到达时,把它所需要的整个运行时间与当前进程的剩余运行时间作比较。如果新的进程需要的时间更少,则挂起当前进程,运行新的进程,否则新的进程等待。
- 轮转调度算法
就绪队列中的每个进程轮流地运行一个时间片,当时间片耗尽时就强迫当前运行进程让出 CPU 资源,转而排到就绪队列尾部,等待下一轮调度。所以,一个进程一般都需要多次轮转才能完成。
轮转调度算法对每个进程都一视同仁,就好比大家都排好队,一个一个来,每个人都运行一会儿再接着重新排队等待运行。
总结:
一个进程中可以有多个线程,它们共享这个进程的资源。
线程又称为迷你进程,但是它比进程更容易创建,也更容易撤销。
引入线程前,进程是资源分配和独立调度的基本单位。引入线程后,进程是资源分配的基本单位,线程是独立调度的基本单位。
进程调度,就是从进程的就绪队列(阻塞)中按照一定的算法选择一个进程并将 CPU 分配给它运行,以实现进程的并发执行
本文来源于: