• 进程、线程、处理机调度


    程序:存放在磁盘中的可执行二进制文件(即*.exe文件,包含一系列指令集合)。是静态的。

    进程:程序的一次执行过程。是动态的。同一个程序多次执行将对应多个进程。

    线程:轻量级进程。一个进程至少有一个线程。

    没有线程的概念之前,进程是资源分配和处理机分配的基本单位。

    有了线程的概念后,进程是资源分配的基本单位,线程是处理机分配的基本单位。

    进程

    程序开始运行时,系统会创建相应的进程,给进程分配唯一的进程ID(PID,Process ID),并创建进程控制块(PCB),分配内存空间。程序运行结束,系统将回收PCB和内存空间。

    注:程序运行的过程,是CPU执行一条一条机器指令的过程(高级语言代码由编译器编译成机器指令)。

    1、进程的组成

    进程控制块(PCB,Process Control Block):【数据结构】

    1、PCB是进程存在的唯一标志。PCB是给操作系统使用,用于管理进程。

    2、PCB中存放操作系统管理进程所需的信息。包括:

    • 基本的进程描述信息:进程标识符PID,用户标识符UID(进程所属用户ID)。用于实现操作系统对各进程的区分。
    • 给进程分配的资源清单:正在使用哪些内存区域,正在使用哪些I/O设备,正在使用哪些文件。用于实现操作系统对资源的管理。
    • 进程控制或管理信息:进程当前状态,CPU运行时间,磁盘使用情况,网络流量使用情况等。用于实现操作系统对进程的控制。
    • 处理机相关信息:各寄存器中的内容(如:程序状态字寄存器PSW,程序计数器PC)。用于实现进程的切换。

    系统给进程分配的内存区域有两部分:程序段(存放程序的代码即指令序列),数据段(存放进程运行过程中产生的各种数据,如:变量)。程序段和数据段是给进程自己使用,与进程自身的运行逻辑有关。

    PCB、程序段、数据段共同组成了进程实体(进程映像)。进程实体反映了进程某一时刻的状态,是静态的。同一个程序多次执行,各进程的PCB和数据段不同,但程序段相同。

    2、进程的特征

    • 动态性。最基本的特征。进程是程序的一次执行过程。程序运行时,创建进程;进程被调度后,进程实体在变化;运行结束后,进程撤销。
    • 并发性。内存内有多个进程,各进程并发执行。多个进程“同时”执行(实际是一个CPU只能执行一个进程,多个进程根据一定策略轮流执行,CPU速度很快,因此感觉多个进程“同时”执行)。
    • 独立性。进程独立运行,独立获得资源。各进程之间不受干扰。
    • 异步性。进程何时被调用,何时暂停,何时结束,执行多长时间,以怎样的速度向前推进,都是不可知的,由操作系统决定。操作系统中的进程同步机制可以解决异步问题。异步性会导致并发性的执行结果的不确定性。
    • 结构性。操作系统为每个进程创建一个PCB。结构上由PCB、程序段、数据段组成。

    3、进程的组织方式:(进程PCB的组织方式)

    • 链式:按进程状态,设置多个队列;操作系统持有指向各队列的指针。
    • 索引方式:按进程状态,设置多个索引表;操作系统持有指向各索引表的指针。

    4、进程状态

    1. 创建态(New):程序开始运行时,操作系统创建相应的进程。进程正在被创建。
    2. 就绪态(Ready):进程创建结束,具备运行条件,但没有空闲的CPU。进程正在等待CPU处理。
    3. 运行态(Running):CPU空闲时,选择一个处于就绪态的进程执行。进程正在被CPU执行。
    4. 阻塞态(Waiting/Blocked):程序运行时,主动请求某事件而让出CPU,等待相应事件完成。进程正在等待主动请求的事件完成。
    5. 终止态(Terminated):程序运行结束或者发生不可修复的错误,操作系统终止该进程。进程正在被撤销。
    6. 挂起态:又称就绪挂起态。将处于就绪态的某进程从内存调出到外存,需要时再调回内存。就绪进程被调出到外存等待的状态。也有进程创建完成后或者时间片到而被挂起。
    7. 阻塞挂起态:将处于阻塞态的某进程从内存调出到外存,需要时再调回内存。阻塞进程被调出到外存等待的状态。

    5、进程控制

    进程控制:进程的创建,进程状态的转换,进程的撤销。通过操作系统内核的原语实现。

    • 原语是特殊的程序,具有原子性(即原语执行中途不会被中断)。
    • 原语通过关中断和开中断两个特权指令实现原子性。

    (1)创建进程:操作系统创建一个进程。使用创建原语。创建态\rightarrow就绪态。

    • 系统为该进程申请空白PCB,分配进程ID即PID。
    • 系统为该进程分配资源(内存区域等)。
    • PCB初始化(将进程ID、父进程ID、用户ID等保存到PCB,程序计数器指向程序的入口地址,进程状态设置为就绪态)。
    • 将该进程放入就绪队列。

    (2)撤销进程:操作系统终止一个进程。使用撤销原语。就绪态/阻塞态/运行态\rightarrow终止态\rightarrow无。

    • 找到该进程的PCB。
    • 若该进程正在运行,立即剥夺CPU,将CPU分配给其他进程。
    • 终止该进程下的所有子进程。
    • 该进程下的所有资源归还给父进程或者操作系统。
    • 删除PCB。

    (3)进程阻塞和进程唤醒  【阻塞原语和唤醒原语必须成对出现】

    ① 进程阻塞:正在运行的进程,主动让出CPU,进入阻塞态,等待特定事件完成。使用阻塞原语。运行态\rightarrow阻塞态。

    • 找到该进程的PCB。
    • 保护进程运行现场。(便于再次运行时恢复运行现场继续往下执行)
    • 将该进程的状态设为阻塞态。暂停进程执行。
    • 将该进程的PCB放入阻塞队列。

    ② 进程唤醒:处于阻塞态的进程,等待的特定事件完成,产生中断,系统将进程唤醒,进程恢复就绪态,重新等待CPU处理。使用唤醒原语。阻塞态\rightarrow就绪态。

    • 找到该进程的PCB。
    • 将该进程的状态设为就绪态。
    • 将该进程的PCB从阻塞队列移除,放入就绪队列。
    • 恢复该进程的运行现场(进程的上下文)。

    (4)进程挂起和进程激活

    ① 进程挂起:内存空间不足或用户要求或父进程要求时,将某进程暂时从内存调出到外存,需要时再调回内存。使用挂起原语。创建态/就绪态/运行态\rightarrow(就绪)挂起态。阻塞态\rightarrow阻塞挂起态。

    注意:进程的PCB常驻内存。

    • 找到该进程的PCB。
    • 申请外存交换区空间,换出到外存,外存地址保存到PCB。
    • 回收该进程的内存空间。
    • 将进程状态设置为就绪/阻塞挂起态,将PCB从原队列转入相应队列。

    ② 进程激活:内存空间充足或用户要求或父进程要求或自身挂起周期结束时,将进程从外存调回内存。使用激活原语。(就绪)挂起态\rightarrow就绪态。阻塞挂起态\rightarrow阻塞态。

    阻塞挂起态的进程调回内存时只能恢复到阻塞态,但若阻塞进程等待的事件发生,则阻塞挂起态\rightarrow就绪挂起态\rightarrow就绪态。

    • 找到该进程的PCB。
    • 申请内存空间,调回到内存。
    • 回收该进程的外存空间。
    • 将进程状态设置为就绪态/阻塞态,将PCB从原队列转入相应队列。

    (5)进程切换:正在运行的进程1,主动或被动地下CPU,进程停止执行;CPU选择另一个进程2执行。即从进程1切换到进程2。使用切换原语。进程1:运行态\rightarrow就绪态/阻塞态/终止态。进程2:就绪态\rightarrow运行态。

    • 进程1的运行环境信息(即进程上下文Context,一些必要的寄存器中的内容)保存到PCB,将PCB放入相应队列。
    • 进程2更新PCB,根据PCB恢复进程运行环境。

    6、进程调度

    多个进程时,系统根据一定策略从就绪队列中选择一个进程,为其分配处理机进行执行,即进程调度。

    广义的进程调度包含选择一个进程和进程切换。

    进程调度的方式:剥夺调度方式(抢占式,进程被动放弃处理机),非剥夺调度方式(非抢占式,进程主动放弃处理机)。

    • 进程被动放弃处理机的情况:时间片到,有更高优先级的进程,处理机有更紧急的事情(处理中断)。
    • 进程主动放弃处理机的情况:进程执行结束,进程出现异常而终止,主动阻塞(等待I/O)。

    不能进程调度的情况:中断处理,原子操作(原语),进程在操作系统内核程序临界区(一般访问某内核数据结构)中。

    进程在访问操作系统内核程序临界资源时,不能进行处理机调度和切换。

    进程访问一般的临界资源(如打印机,CPU可以执行其他进程),可以进行处理机调度和切换。

    调度算法,详见后面的补充。

    7、进程的通信

    内存中有多个进程,进程可以访问自己的内存空间,不能访问其他进程,如果进程之间需要数据传递,可有以下方式:共享存储、消息传递、管道。

    (1)共享存储

    操作系统划分一块公共区域(即共享存储区),来实现进程之间的数据交换。操作系统提供同步互斥工具,由各进程实现互斥的访问共享空间(即一个进程访问共享空间时,其他进程不能同时访问)。

    • 基于存储区的共享:各共享进程将公共区域映射到自己的虚拟地址空间(即进程的虚拟地址空间包括进程自身的地址空间和公共内存空间),数据形式和位置由进程控制,灵活性高,速度快。
    • 基于数据结构的共享:不仅划分公共区域,还规定了固定的数据结构,灵活性差,速度慢。

    (2)消息传递

    消息:包括消息头(含发送进程ID、接收进程ID、消息长度等格式化的信息)和消息体(具体传递的数据)。

    进程通过操作系统提供的发送消息和接收消息两个原语实现数据交换。

    ① 直接通信方式

    操作系统内核保存着各进程的PCB。进程之间直接指明对方进程(即发送进程指明发送给谁,接收进程指明从谁那接收)。

    发送进程通过发送原语send发送消息,系统将消息放入接收进程PCB中的消息队列;接收进程通过接收原语receive接收消息,系统检查接收进程PCB中的消息队列,将对应消息放入接收进程的内存空间中。

    ② 间接通信方式

    通过中间实体即操作系统内核中的“信箱”实现中转。进程之间不指明对方进程,但指明哪个“信箱”。

    发送进程向系统申请信箱,通过发送原语send将消息放入信箱,接收进程通过接收原语receive去信箱接收消息。

    (3)管道通信

    管道:特殊的共享文件,又称pipe文件,实际是内存中大小固定的内存缓冲区,类似“循环队列”。同一时刻,数据流向只能是单向的(即半双工通信),而且先进先出。若要双向同时通信(即全双工通信),需要两个管道。

    • 由操作系统实现进程互斥地访问管道。
    • 即使管道有数据,写进程也可以写数据;管道写满时,写进程将被阻塞;数据被读走,将唤醒写进程。
    • 只要管道有数据,读进程就可以读数据;管道读空时,读进程将被阻塞;数据被写入,将唤醒读进程。
    • 允许多个写进程往管道中写入数据,也允许多个读进程从管道读数据,但一旦数据读出将丢失,多个读进程容易导致数据错乱,多个写进程可能覆盖数据。
    • 管道与共享存储区的区别是:① 共享存储区的数据由进程决定可随意存放,但管道只能先进先出,类似循环队列。② 共享存储区的互斥访问由进程自己实现,但管道的互斥访问由操作系统实现。

    8、进程同步、进程互斥

    进程同步:又称直接制约关系。各进程之间需要按一定顺序协调地完成某任务。

    进程互斥:又称间接制约关系。一个进程在访问临界资源,另一个进程只能等待;一个进程访问结束,另一个进程才能访问。

    临界资源:一个时间段内,只能一个进程使用的资源。

    例如:物理设备(摄像头,打印机),变量,数据,内存缓冲区等都可能是临界资源。

    进程互斥的代码由四部分组成:

    • 进入区:检查是否进入临界区。若进入临界区,设置“正在访问临界资源的标志”(即上锁)。
    • 临界区:又称临界段。访问临界资源。
    • 退出区:使用完临界资源,退出临界区。解除“正在访问临界资源的标志”(即解锁)。
    • 剩余区:其他代码部分。

    进程互斥需遵循的原则:

    • 空闲让进:若资源空闲,允许一个进程立即访问。
    • 忙则等待:若资源正在被访问,进程必须等待。
    • 有限等待:进程需要在有限的时间内进入临界区,避免饥饿。
    • 让权等待:若进程不能进入临界区,需释放处理机,避免忙等。

    进程互斥的实现方法:(软件、硬件)

    进程互斥的软件实现方法
    单标志法双标志先检查法双标志后检查法Peterson算法

    设置一个整型变量:

    允许使用临界资源的进程号。

    设置一个布尔型数组:

    各元素标记各进程使用临界资源的意愿。

    设置一个布尔型数组:

    各元素标记各进程使用临界资源的意愿。

    设置两个变量:

    各进程使用临界资源的意愿(数组),允许使用临界资源的进程号(整型)。

    ① 先检查允许进入临界区的进程号是否是自己的进程号。

    ② 若是自己,则访问临界区。

    ③ 访问结束,将允许进入临界区的进程号设置为其他进程号。

    ① 先检查别的进程是否想要进入临界区。

    ② 若没有,则上锁(自己的意愿标记为True)。开始访问临界区。

    ③ 访问结束,则解锁(将自己的意愿标记为False)。

    ① 先上锁(自己的意愿标记为True)。

    ② 检查别的进程是否想要进入临界区。若没有,开始访问临界区。

    ③访问结束,则解锁(将自己的意愿标记为False)。

    结合单标志法和双标志法。

    ① 先将自己的意愿标记为True。允许访问的进程号设为其他进程号。

    ② 检查别的进程是否想要进入临界区以及允许访问的进程号是否是别的进程。若没有,开始访问临界区。

    ③访问结束,则将自己的意愿标记为False。

    违反“空闲让进”的原则。

    检查和上锁不能一气呵成,可能被中断。

    违反“忙则等待”的原则。

    检查和上锁不能一气呵成,可能被中断。

    违反“空闲让进”和“有限等待”的原则。

    未遵循“让权等待”的原则。

    进程互斥的硬件实现方法
    中断屏蔽方法TestAndSet指令(TS指令)Swap指令(XCHG指令)
    关中断/开中断指令硬件实现。记录临界资源是否正在被使用。逻辑上与TS指令类似。

    ① 关中断。

    ② 访问临界资源。

    ③开中断。

    ① 检查临界资源是否正被访问(即是否上锁)。无论是否上锁,现在上锁。

    ② 若原来未上锁,则访问临界资源。若原来已上锁,等待上一个进程访问结束解锁。

    ③访问结束,解锁。

    逻辑上与TS指令类似。

    简单高效。

    但不适合多处理机,不适合用户进程。只适用于操作系统内核进程。

    实现简单。适合多处理机。

    不满足“让权等待”的原则。

    逻辑上与TS指令类似。

    同步互斥工具:

    (1)锁(或互斥锁)

    互斥锁:一个变量(可以是整数,也可以是布尔值),确保同一时间只能一个进程访问临界资源。状态:未锁,已锁。

    需要循环等待的互斥锁,又称自旋锁,例如:TS指令、Swap指令、单标志法。

    缺点是忙等,违反“让权等待”的原则。优点是进程等待不需要切换进程上下文,常用于多处理机。

    通常用硬件实现互斥锁。

    (2)信号量

    信号量:一个变量(可以是整数,也可以是记录型变量)。表示系统中某资源的数量。

    通过wait(s)原语(简称P(s)操作)和signal(s)原语(简称V(s)操作)来实现进程互斥、进程同步。

    ① 整型信号量

    整数变量:表示信号量,记录系统中某资源的数量。

    P操作:检查资源数量,若没有空闲资源,则循环等待;若有空闲资源,则使用一个资源,资源数量-1。

    V操作:资源使用完,释放资源,资源数量+1。

    ② 记录型信号量

    整数变量:记录系统中某资源的剩余数量。等待队列:记录等待使用该资源的进程。

    P操作:检查资源剩余数量,若有空闲资源,则使用一个资源,资源剩余数量-1;若没有空闲资源,使用block原语将进程放入等待队列。

    V操作:资源使用完,释放资源,资源剩余数量+1。若资源有空闲且等待队列有进程,则使用wakeup原语唤醒一个进程使用该资源。

    使用信号量机制实现进程互斥:

    设置互斥信号量,初始值为1。不同的临界资源设置不同的互斥信号量。

    P操作:进入区,申请资源。V操作:退出区,释放资源。P操作、V操作成对使用。

    使用信号量机制实现进程同步:

    设置同步信号量,初始值为0。每一对“一前一后”的同步关系设置一个同步信号量。

    先执行的“前操作”,释放资源,即V操作。后执行的“后操作”,申请资源,即P操作。

    前驱关系:多个“一前一后”的同步关系。

    (3)管程

    管程:一个特殊模块。类似面向对象中的类。

    • 管程有自己的名字。
    • 只用于管程内部的共享数据结构。
    • 对共享数据结构设置初始值。
    • 管程内部有一组对数据结构进行操作的过程。

    管程的特点:

    • 只能通过管程内的过程访问共享数据结构。
    • 每次只允许一个进程在管程内执行某个过程。

    进程同步、进程互斥相关的问题:

    (1)生产者-消费者问题:

    • 缓冲区不满,则生产者往缓冲区写数据。  【同步问题】
    • 缓冲区不空,则消费者从缓冲区读数据。 【同步问题】
    • 缓冲区,只能互斥访问。  【互斥问题】

    解决:① 设置2个同步信号量,初始值为对应资源的初始值。② 设置1个互斥信号量。

    注意:申请互斥信号量必须在申请同步信号量之后,否则会导致死锁(双方都被阻塞,都在等对方释放资源)。

    (2)多生产者-多消费者问题:

    • 生产者1往缓冲区写数据1,然后消费者1从缓冲区读数据1。  【同步问题】
    • 生产者2往缓冲区写数据2,然后消费者2从缓冲区读数据2。  【同步问题】
    • 缓冲区有剩余空间,则生产者写数据。  【同步问题】
    • 缓冲区,只能互斥访问。  【互斥问题】

    解决:① 设置3个同步信号量,初始值为对应资源的初始值。② 设置1个互斥信号量。

    注意:1、所有同步信号量的值最多为1,即使并发执行,也最多有一个进程能访问临界资源,则可以不设置互斥信号量。2、从“事件”的角度分析。

    (3)吸烟者问题:

    • 1个生产者提供材料组合,3个抽烟者轮流抽烟。
    • 抽烟者发出抽烟结束信号,生产者开始提供下一个。  【同步问题】
    • 3个抽烟者分别只接受材料组合一、材料组合二、材料组合三。  【同步问题】
    • 缓冲区互斥访问。  【互斥问题】

    解决:① 设置4个同步信号量,初始值为对应资源的初始值。② 1个整型变量。③ 互斥信号量此处可省略(因缓冲区大小为1,所有同步信号量的数量最多为1,最多有一个进程可访问临界资源)。

    (4)读者-写者问题:

    • 多个读者可同时读数据。读者之间不互斥。
    • 一个写者在写数据之前和写数据过程中,其他写者和读者都不能使用。【互斥问题】
    • 即写者与写者互斥,写者与读者互斥,读者之间不互斥。

    解决:① 设置3个互斥信号量,初始值为对应资源的初始值。② 1个整数型变量(计数器)。

    (5)哲学家进餐问题:

    同时需要2个资源。可能导致死锁。

    9、死锁

    死锁:两个或两个以上的进程持有各自的资源,又在等待对方的资源,导致彼此都不能执行下去,进程都处于阻塞态。

    饥饿:一个或多个进程,长期得不到某资源,导致无法执行,进程可能处于阻塞态也可能就绪态。

    死循环:一个正在执行的进程,有时因自身逻辑bug问题,一直跳不出某循环,无法正常执行下去。

    死锁发生的条件:互斥条件,不可剥夺条件,请求和保持条件,循环等待条件。

    即某资源,一个时间段内,只能一个进程访问,访问过程中资源不能被强制剥夺,只能进程主动放弃资源;各进程自身已经持有一些资源,仍请求对方进程占有的资源,导致都在等待对方的资源,形成一个循环等待链,各进程都被阻塞。因此发生死锁。

    死锁则一定循环等待,循环等待则不一定死锁。

    死锁则系统一定处于不安全状态,系统处于不安全状态则不一定死锁。系统处于安全状态则一定不会死锁。

    死锁的处理策略:

    (1)预防死锁:(静态策略)。破坏发生死锁的4个条件。

    • 破坏互斥条件:使用SPOOLing技术(假脱机技术),使得独占资源变成共享资源。缺点:实际中为了系统安全,很多资源必须互斥地访问,很多时候无法破坏互斥条件。
    • 破坏不可剥夺条件:如果某些资源被其他进程占有、无法得到所有需要的资源,则:① 主动将已有的资源全部释放,以后再重新申请;② 经操作系统协助,强行从其他优先级低的进程那剥夺需要的资源。缺点:实现复杂、使已完成的工作失效、增加系统开销、可能导致进程饥饿,只适合易保存易恢复的资源。
    • 破坏请求和保持条件:获得所有资源以后才能运行,直到运行结束才释放资源。缺点:浪费资源、导致资源利用率低、可能导致进程饥饿。
    • 破坏循环等待条件:给资源编号,按编号从小到大申请资源,占有编号大的资源就不能申请编号小的资源。缺点:不利于增加资源、不利于编程、会导致资源浪费。

    (2)避免死锁:(动态策略)。在资源分配之前,计算系统的安全性。通过银行家算法,分析是否存在安全序列。若存在一个或多个安全序列,则系统处于安全状态,则分配资源;若不存在安全序列,有可能发生死锁,则不分配资源,如果有进程提前归还资源,系统有可能重新回到安全状态。

    安全序列:按照这种序列分配资源,可以使所有进程都能顺利执行结束。安全序列可能有多个。

    安全性算法:

    1. 检查资源剩余数量是否满足某个进程的需要,若满足,则资源分配给该进程,该进程执行结束可回收所有资源。
    2. 重复第1步,分析其他进程,判断最终是否能得到一个安全序列。

    银行家算法:

    1. 检查某进程申请的资源数量是否在之前声明的最大需求范围内。
    2. 检查资源剩余数量是否满足该进程的申请数量。
    3. 尝试分配资源,尝试更改数据结构,通过安全性算法预判是否存在安全序列。
    4. 若存在安全序列,则系统处于安全状态,系统可以将资源分配给该进程。若不存在安全序列,则系统处于不安全状态,可能发生死锁,则不分配资源。

    银行家算法涉及的数据结构:

    • 二维矩阵:记录各进程声明的对各资源的最大需求数量。
    • 二维矩阵:记录各进程已经分配的各资源数量。
    • 二维矩阵:记录各进程最多还需要分配的各资源数量。
    • 一维数组:记录各资源的剩余数量。
    • 一维数组:记录进程本次申请的各资源数量。

    (3)死锁的检测和解除:通过资源分配图(数据结构)记录资源的申请和分配情况,按照一定算法,检测是否处于死锁状态。若处于死锁状态,则解除死锁。

    死锁定理:某时刻,系统在简化资源分配图后,仍有无法消除的边,则图不可完全简化,表示发生了死锁。

    死锁进程:在简化资源分配图后,仍存在有向边的进程。

    资源分配图:

    • 2种节点(一个进程一个节点、一类资源一个节点)。
    • 2种有向边(进程申请资源的请求边、资源已经分配给进程的分配边)。

    死锁检测:(简化资源分配图)

    1. 不阻塞且不是孤点的进程,若执行结束会回收资源,则消除其所有边。
    2. 将回收的资源分配给阻塞的进程,进程不再阻塞则消除其所有边。
    3. 若所有边都消除,则图可完全简化,表示没有发生死锁。若存在无法消除的边,则图不可完全简化,表示发生了死锁。

    死锁解除:

    • 资源剥夺:将某进程挂起(调出到外存),剥夺其资源 分配给其他死锁进程。需防止挂起的进程饥饿。
    • 撤销/终止进程:将某进程或多个进程直接终止,回收其资源。实现简单但代价大。
    • 进程回退:将各进程回退到发生死锁之前。需记录进程历史信息,设置还原点。

    死锁解除选择哪个进程收回其资源:

    • 优先级低的进程。
    • 已经执行的时间比较短的进程。
    • 还需要执行很长时间才能结束的进程。
    • 已经占用的资源比较少的进程。
    • 优先选择批处理式的进程而不是交互式的进程。

    线程

    线程是“轻量级进程”。线程有用户级线程和内核级线程两种。内核级线程是处理机分配的单位。

    • 一个进程可以有多个线程,各线程执行不同任务。
    • 每个线程都有线程ID、线程控制块(TCB)。
    • 线程也有就绪态、阻塞态、运行态三种基本状态。
    • 同一个进程中,各线程共享进程的资源。线程本身几乎没有资源。
    • 同一个进程中,由于共享内存资源,各线程之间通信方便。
    • 同一个进程中,各线程可以被多个处理机同时处理。
    • 同一个进程中的线程切换,不会引起进程切换,开销小。不同进程中的线程切换,会引起进程切换,开销大。

    线程控制块(TCB,Thread Control Block):【数据结构】

    1、用于管理线程。

    2、包括线程标识符(TID,Thread ID)、线程运行状态、优先级、用于切换的处理机信息(程序计数器PC、必要的寄存器、堆栈指针)。

    3、通过线程表将各线程组织起来。可多个TCB组成一张线程表。

    线程
    用户级线程内核级线程
    用户视角操作系统视角
    处于用户态处于内核态
    由用户进程通过线程池管理由操作系统内核管理
    用户级线程切换不需要操作系统转到内核态内核级线程切换从用户态转到内核态,由操作系统内核完成
    操作系统不知道用户级线程的存在操作系统支持的线程,CPU分配的单位
    多线程模型
    一对一多对一多对多
    一个用户级线程映射到一个内核级线程多个用户级线程映射到一个内核级线程n个用户级线程映射到m个内核级线程(n\geqm)
    一个进程对应多个内核级线程一个进程对应一个内核级线程一个进程对应多个内核级线程

    一个线程阻塞,其他线程可以继续执行,并发度高。

    但线程切换需要切换到内核态,管理成本高,开销大

    线程切换不需要切换到内核态,开销小。

    但一个线程阻塞,整个进程阻塞,并发度低。

    一个线程阻塞,其他线程可以继续执行,所有内核级线程都阻塞进程才阻塞。并发度高。

    且减小开销。

    补充:

    注:有了线程的概念后,在CPU上运行的是线程。

    处理机调度
    高级调度:作业调度中级调度:内存调度低级调度:进程调度
    面向作业面向进程面向进程
    外存\rightarrow内存外存\rightarrow内存内存\rightarrowCPU

    \rightarrow创建态\rightarrow就绪态

    (就绪)挂起态\rightarrow就绪态,

    阻塞挂起态\rightarrow阻塞态,

    阻塞挂起态\rightarrow(就绪)挂起态\rightarrow就绪态【阻塞事件已发生】

    就绪态\rightarrow运行态
    频率:低频率:中频率:高
    按照某种规则,从后备队列中选择合适的作业,将其从外存调入内存,并为其创建进程按照某种规则,从挂起队列中选择合适的进程,将其从外存调回内存按照某种规则,从就绪队列中选择合适的进程,为其分配处理机

    调度算法的评价指标:

    • CPU利用率:CPU执行任务的时间占总时间的比例。
    • 系统吞吐量:单位时间完成任务的数量。
    • 响应时间:用户首次提出请求,到系统首次给出响应所需的时间。
    • 等待时间:等待CPU处理所需的时间。(作业)等待时间包括作业在后备队列等待作业调度的时间、进程在就绪队列等待进程调度的时间。(进程)等待时间包括进程在就绪队列等待进程调度的时间。
    • 周转时间:任务提交到系统,到任务完成所需的时间。包括作业在后备队列等待作业调度的时间、进程在就绪队列等待进程调度的时间、进程在CPU上的执行时间、进程等待I/O操作完成的时间。

    CPU利用率=CPU忙碌时间/总时间。

    系统吞吐量=完成作业数量/花费的总时间。

    (作业)周转时间=作业完成时间-作业提交时间。

    平均周转时间=各作业周转时间总和/作业数量。

    带权周转时间=作业周转时间/作业实际运行时间。

    平均带权周转时间=各作业带权周转时间总和/作业数量。

    调度算法:

    1、先来先服务(FCFS,First Come First Serve)

    • (作业)先到达后备队列先进行作业调度。(进程)先到达就绪队列先进行进程调度。
    • 非抢占式调度。
    • 简单公平,但对排在后面的短作业不利。
    • 不会导致饥饿。

    2、短作业优先(SJF,Shortest Job First),短进程优先(SPF,Shortest Process First)

    • 作业/进程执行时间短的先进行调度。
    • 默认是非抢占式调度。一个进程执行完,优先挑选剩余运行时间短的执行。
    • 也有抢占式调度(最短剩余时间优先算法,SRTN,Shortest Remaining Time Next)。新进程到达时,正在运行的进程和新进程哪个剩余运行时间短,哪个先执行;正在运行的进程执行完,优先挑选剩余运行时间短的执行。
    • “最短”平均等待时间、平均周转时间。
    • 执行时间长的作业/进程可能导致饥饿。

    3、高响应比优先(HRRN,Highest Response Ratio Next)

    • 一个进程执行完,优先挑选响应比高的执行。响应比=(等待时间+运行时间)/运行时间。
    • 非抢占式调度。
    • 既考虑等待时间又考虑运行时间。
    • 不会导致饥饿。

    以上3种调度算法,不关注响应时间,不区分任务的紧急情况,适用于早起的批处理系统。

    4、时间片轮转(RR,Round-Robin)

    系统设定时间间隔,就绪队列的每个进程依次执行,时间片时,时钟装置会发出时钟中断通知CPU,进程被强行剥夺CPU、放入就绪队列的队尾,CPU处理下一个进程(就绪队列队头的进程)。进程运行结束主动放弃CPU,也会发生调度。

    • 用于进程调度。
    • 抢占式调度。
    • 不会导致饥饿。
    • 常用于分时操作系统,响应快。但时间片设计太大,将退化为先到先服务。时间片太小,进程切换频繁,系统开销大。一般时间片设计时进程切换的开销占比不超过1%。

    5、优先级调度算法

    优先级设置有两种:只在进程创建时确定优先级(静态优先级)。进程创建时优先级设定初始值,若进程等待时间很长、运行时间很长、频繁I/O操作,则适当动态调整优先级(动态优先级)。

    优先级:系统进程>用户进程,前台进程>后台进程,I/O繁忙型(I/O型)>CPU繁忙型(计算型)。

    • 作业/进程有各自的优先级,调度优先级高的。
    • 非抢占式调度。一个进程执行完,调度优先级高的。
    • 抢占式调度。新进程到达时,新进程的优先级若比正在执行的进程优先级高,CPU会先处理优先级高的新进程。正在运行的进程执行完,调度优先级高的执行。
    • 优先级低的进程会导致饥饿。
    • 适用于实时操作系统。

    6、多级队列调度算法

    系统根据进程类型设置多个队列,进程创建时,放入对应的队列。

    各队列可设置不同优先级,按优先级依次调度。也可以给各队列分配不同的时间片。

    各队列可使用不同的调度策略。例如:系统进程队列可使用优先级调度。交互式队列可使用时间片调度。批处理队列可使用先到先服务。

    7、多级反馈队列调度算法

    • 设置多级就绪队列。各队列依次优先级从低到高,时间片从小到大。。
    • 新进程到达时,放入第1级队列。
    • 时间片到,第k级队列的进程放入第k+1级队列的队尾。若已是最低级队列,则放回原队列队尾。
    • 被优先级高的进程抢占,则放回原队列队尾。
    • 第k级队列为空,第k+1级队列的进程才执行。

    用于进程调度。抢占式调度。会导致饥饿。

  • 相关阅读:
    react导出excel?
    算法——字符串(1)
    最短路与动态规划(一)
    sql注入的其他注入
    java版工程管理系统Spring Cloud+Spring Boot+Mybatis实现工程管理系统源码
    JS正则表达式
    su root失败 sudo su成功进入root
    [mysql]游标和触发器
    C语言_函数指针数组的应用
    Nexus-3.41.1安装
  • 原文地址:https://blog.csdn.net/yannan20190313/article/details/133687939