操作系统-进程篇1(进程/线程)

一、进程的描述

1. 进程定义

进程:一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程。(程序是一个静态的过程,进程是一个动态过程)

2. 进程的组成

一个进程包括:程序的代码、程序处理的数据、程序计数器中的值(指示下一条将要运行的程序指令)、通用寄存器的当前值(堆、栈)、一组系统资源(如打开的文件)

总之,进程包含了正在运行的一个程序的所有状态信息。

进程和程序的关系:

  • 程序是产生进程的基础
  • 程序的每次运行构成不同的进程
  • 进程是程序功能的体现
  • 通过多次执行,一个程序可对应多个进程;通过调用关系,一个进程可以包括多个程序。
  • 进程是动态的,程序是静态的(程序是有序代码的集合,进程是程序的执行,有核心态和用户态)
  • 进程是暂时的,程序是永久的(进程的状态会发生变化,程序可以永久保存)
  • 进程和程序组成不同,进程组成包括程序、数据和进程控制块(进程状态信息

3. 进程的特点

动态性:可动态的创建、结束进程

并发性:进程可以被独立调度并占用处理机运行(一段时间内,可以有多个进程在处理执行)

独立性:不同进程的工作不相互影响(通过页表控制程序只能访问合法的内存空间,越界访问会产生异常)

制约性:因访问共享数据/资源/或者进程间同步而产生制约。(进程间同步/互斥)

4. 进程控制结构

a. 进程控制块(PCB)

操作系统管理进程运行所用的信息集合。操作系统用PCB来描述进程的基本情况以及运行变化的过程,PCB是进程存在的唯一标志。(与进程是一对一关系)

b. PCB功能

  • 进程的创建:为该进程生成一个PCB
  • 进程的终止:回收它的PCB
  • 进程的组织管理:通过对PCB的组织管理来实现

c. PCB的组成

进程标识信息:本进程的标识;本进程的产生者的标识(父进程标识);用户标识

处理机状态信息保存区(保存进程运行的现场信息):

  • 用户可见寄存器:用户程序可以使用的数据,地址等寄存器);
  • 控制和状态寄存器:程序计数器(PC),程序状态字(PSW);
  • 栈指针:过程调用/系统调用/中断处理与返回时使用

进程控制信息:

  • 调度和状态信息:用于操作系统调度进程并占用处理机使用
  • 进程间通信信息:为支持进程间的与通信相关的各种标识、信号、信件等,这些信息存放在接收方的进程控制块中。
  • 存储管理信息:包含有指向本进程映射存储空间的数据结构
  • 进程所用资源:说明由进程打开、使用的系统资源(如打开的文件等)
  • 有关数据结构连接信息:进程可以连接到一个进程队列中,或连接到相关的其他进程PCB(父子进程关系)

PCB组织方式:

链表:同一状态的进程其PCB成一个链表,多个状态对应多个不同的链表(各状态的进程形成不同的链表:就绪链表、阻塞链表)

索引表:同一状态的进程归入一个index表(由index执行PCB),多个状态对应多个不同的index表(各状态进程形成不同的索引表:就绪索引表、阻塞索引表)

二、进程的状态

1. 进程生命周期管理

a. 进程创建

引起进程创建的3个主要事件:

  • 系统初始化
  • 用户请求创建一个新进程
  • 正在运行的进程执行了创建进程的系统调用

b. 进程运行

操作系统会选择一个就绪的进程进行执行

问题:如何选择 -> 调度算法

c. 进程等待(由于资源等原因需要等待)

在以下情况,进程等待(阻塞):

  • 请求并等待系统服务,无法马上完成
  • 启动某种操作,无法马上完成(等待其他进程执行完成等)
  • 需要的数据没到达

进程只能自己阻塞自己,因为只有进程自身才能知道何时需要等待某种事件的发生

d. 进程唤醒(资源等外界因素就绪,进程唤醒)

唤醒的原因:

  • 被阻塞进程需要的资源可被满足
  • 被阻塞的进程等待的事件到达
  • 将改进程的PCB插入到就绪队列

进程只能被别的进程或者操作系统唤醒

e. 进程结束

在以下四种情况,进程结束:

  • 正常退出(自愿)
  • 错误退出(自愿)
  • 致命错误(强制性)
  • 被其他进程杀死(强制性)

2. 进程状态变化模型

进程的三种基本状态:

进程在生命结束之前处于且仅处于三种基本状态之一,不同系统设置的进程状态数目不同

  • 运行态(Running):当一个进程正在处理机上运行的状态
  • 就绪态(Ready):一个进程获得了除了处理机之外的一切所需资源,一旦得到处理机即可运行
  • 等待状态(Blocked):一个进程正在等待某一事件而暂停运行(等待某资源、等待输入/输出完成)

三状态变化图:

进程其他的基本状态:

  • 创建状态:一个进程正在被创建,还没被转到就绪状态之前的状态
  • 结束状态:一个进程正在从系统中消失时的状态,这是因为进程结束或者由于其他原因所导致的

五状态变化图:

状态变化解释:

  • NULL -> New:一个新进程被产生出来执行一个程序
  • New -> Ready:当进程被创建完成并初始化后,一切就绪,准备运行时,变为就绪态(PCB初始化)
  • Ready -> Running:处于就绪状态的进程被进程调度程序选中后,分配到处理机上执行
  • Running -> Exit:进程完成或者因为出错被操作系统处理
  • Running -> Ready:处于运行状态的进程在其运行过程中,时间片用完,让出处理机 (由操作系统完成)
  • Running -> Blocked:当进程请求某种资源必须等待时,让出处理机
  • Blocked -> Ready:当进程等待的事件到达,从阻塞态变为就绪态

3. 进程挂起模型

a. 概述

定义:进程在挂起状态时,意味着进程没有占用内存空间(被替换到硬盘上)。处于挂起状态的进程映像在磁盘上。

b. 挂起状态转换

挂起状态:

  • 阻塞挂起状态:进程本身是阻塞态的(等待某事件到达)
  • 就绪挂起状态:进程在外存,但只要进入内存,即可运行

与挂起相关的状态转换:

  • 阻塞 -> 阻塞挂起:没有进程处于就绪状态或者就绪进程需要更多的内存资源时,会进行这种转换,以提交新进程或运行就绪进程
  • 就绪 -> 就绪挂起:当有高优先级阻塞(系统认为会很快就绪的)进程和低优先就绪进程时,系统会选择挂起低优先级就绪进程
  • 运行 -> 就绪挂起:对抢占式分时系统,当有高优先级阻塞挂起进程因为事件就绪而进入就绪挂起时,系统可能会把运行进程转到就绪挂起状态

在外存时的状态转换:

阻塞挂起 -> 就绪挂起:当有阻塞挂起进程因事件到达后,系统会把阻塞挂起进程转换为就绪挂起进程

解挂/激活(把一个进程从外存转入内存,可能有以下几种情况):

  • 就绪挂起 -> 就绪:没有就绪进程或者挂起就绪进程优先级高于就绪进程时
  • 阻塞挂起 -> 阻塞:当一个进程释放掉足够内存时,系统会把一个高优先级阻塞挂起进程转换为阻塞进程

c. 状态队列

定义:

  • 操作系统维护一组队列,用来表示系统当中所有进程的当前状态
  • 不同状态用不同队列来表示(就绪队列、各种类型阻塞队列等)
  • 每个进程的PCB都根据它的状态加入相应的队列中,当一个进程状态发生变化,它的PCB从一个状态队列中脱离出来,加入到另一个队列

三、线程

1. 为什么使用线程

多进程程序的问题:维护进程的系统开销较大,创建进程时,需要分配资源、建立PCB;撤销进程时,需要回收资源、撤销PCB;进程切换时,需要保存当前进程的状态信息

针对多进程程序的问题,提出以下实体,满足以下特征:

  • 实体之间可以并发的执行
  • 实体之间共享相同的地址空间(进程间不能直接共享地址空间,需要操作系统拷贝数据)

2. 什么是线程

a. 简介

定义:进程当中的一条执行流程

TCB(线程控制块):线程控制块只负责管理和执行流程相关的信息,包括(PC程序计数器、SP堆栈、寄存器信息、状态信息),堆空间、代码段、数据段是共享的

线程所需要的资源:

b. 线程与进程

从两个方面重新理解进程:

  • 从资源组合的角度:进程把一组相关的资源组合起来,构成了一个资源平台(环境),包括地址空间(代码段、数据段),打开的文件等各种资源
  • 从运行的角度:代码在这个资源平台上的一条执行流程(线程)

线程与进程关系:

  • 一个进程可能有多个线程
  • 一个进程下的线程共享进程提供的资源平台(线程可以访问进程下的代码/数据/内存等)

线程与进程的比较:

  • 进程是资源分配单位,线程是CPU调度单位
  • 进程拥有一个完整的资源平台,线程只独享必要的资源(寄存器/栈)
  • 线程同样具有就绪、阻塞和执行三种基本状态,同样具有状态之间的转换
  • 线程能减少并发执行的时间和空间开销(线程创建时间比进程短 / 线程终止时间比进程短 / 同一进程内的线程切换时间比进程短,进程间调度需要切换页表,线程不需要 / 由于同一进程的各线程间共享内存和文件资源,可不通过内核进行数据交换)

c. 线程的优缺点

线程的优点:

  • 一个进程可以同时存在多个线程
  • 各个线程之间可以并发的执行
  • 各个线程之间可以共享地址空间和文件等资源

线程的缺点:一个线程崩溃,会导致其所属的进程的所有线程崩溃

3. 线程的实现

a. 线程的实现方式

  • 用户线程:在用户空间实现
  • 内核线程:在内核中实现(windows / linux)
  • 轻量级线程:在内核中实现,支持用户线程

b. 用户线程与内核线程

用户线程:由应用程序的库实现多线程,由应用程序进行线程管理

内存线程:用操作系统来完成线程管理

用户线程与内核线程的对应关系:

  • 多对一(多个用户线程对应一个内核线程)
  • 一对一(一个用户线程对应一个内核线程)
  • 多对多(n个用户线程对应m个内核线程)

c. 用户线程实现

定义:不依赖操作系统的内核,由一组用户级线程库函数来实现的一种线程机制,包括线程的创建、终止、同步和调度

特点:

  • 由于用户线程的维护由相应进程来完成,不需要操作系统内核了解用户线程的存在,可以用于不支持线程技术的多进程操作系统
  • 每个进程都需要自己私有的TCB列表来跟踪每个线程的状态信息(PC、栈指针、寄存器),TCB由线程库函数来维护
  • 用户线程的切换也是由线程库函数来完成,无需用户态/核心态切换,速度快
  • 允许每个进程拥有自定义的线程调度算法

用户线程缺点:

  • 在用户线程中,阻塞性的系统调用如何实现?如果一个线程发起系统调用阻塞了,会导致整个进程阻塞(操作系统无法感知用户线程,只能以进程形式进行调度)
  • 当一个线程开始运行后,除非它主动交出cpu使用权,否则它所在的进程中其他的线程将无法运行(用户态线程库无法主动打断线程执行,操作系统可以通过时钟中断完成切换)
  • 由于时间片分配给进程,因此与其他进程相比,多线程执行时,每个线程得到的时间片较少,执行较慢

d. 内核线程的实现

定义:在操作系统内核当中实现的一种线程机制,由操作系统的内核来完成线程的创建、终止和管理

特点:

  • 在支持内核线程的操作系统中,由内核来维护进程和线程上下文信息(PCB管理TCB列表)
  • 线程的创建、终止和切换通过系统调用/内核函数的方式来进行,由内核来完成,因此系统开销较大
  • 在一个进程中,如果某个内核线程发起系统调用而被阻塞,并不会影响其他内核线程的运行
  • 时间片分配给线程,多线程的进程获得更多CPU时间

e. 轻量级进程

定义:内核支持的用户线程,一个进程可有一个或多个轻量级进程,每个轻量级进程由一个单独的内核线程来支持

4. 上下文切换

定义:停止当前运行进程(从运行状态改变成其他状态)并且调度其他进程(转变成运行状态)

要求:

  • 必须在切换之前存储许多部分的进程上下文
  • 必须能够在之后恢复他们,且进程不能显示该进程曾经被暂停过
  • 必须快速(上下文转换时非常频繁)

上下文内容:寄存器(PC、SP ... ...),CPU状态;上下文切换时,可以从PCB中取出

5. 进程控制

a. 进程的创建

父进程与子进程:

进程A创建另一个进程B,此时A称为父进程,B称为子进程。子进程可以继承父进程的资源,当子进程撤销后,父进程回收分配给子进程的资源;撤销父进程时,子进程也会撤销

进程创建的原因:终端用户登录系统、作业调度、系统提供服务、用户程序的应用请求等

进程创建的过程(fork):

  1. 为新进程分配一个唯一的进程标识号,并申请一个空白的PCB
  2. 为进程分配资源,为新进程程序、数据、以及用户栈分配必要的内存空间,若资源不足,则进入阻塞状态,等待资源到达
  3. 初始化PCB:初始化标志信息、处理机状态信息、处理机控制信息,设置进程优先级等
  4. 如果就绪队列允许进程进入,则将新创建的进程加入就绪队列,等待被调度

b. 进程的加载与执行(exec)

1) 例子

  • 若pid=0,当前执行空间是子进程,执行了exec成功后,子进程被覆盖,printf("why would i execute") 不会被执行;若exec执行失败,则执行
  • 若pid>0,当前执行空间是在父进程,wait(pid) 为等待子进程执行完毕,wait返回,子进程执行完毕
  • 若pid=0,fork失败

解析:

     执行exec>>>    

  • 当执行exec时,子进程代码、数据替换为calc函数,但pid没变

内存布局图:

    执行fork>>>    

                                                        执行完exec后>>>  

  • 执行fork之后,子进程地址空间复制父进程;执行完exec之后,子进程PCB发生变化,用户态代码段被新程序替换

2) 总结

exec系统调用解析:

  • exec()调用允许一个进程加载一个不同的程序并在main开始执行(事实上 _start)
  • 它允许一个进程指定参数的数量(argc)和它的字符串参数数组(argv)
  • 若调用成功,其pid不变,当运行了一个不同的程序
  • 代码,堆(heap)和栈(stack)重写

fork系统调用解析:

  • 为子进程分配内存
  • 复制父进程的内存和CPU寄存器到子进程里
  • 系统开销较大
  • 在大多数情况下,在调用fork()之后会调用exec(),fork()操作中内存复制往往是没有作用的,且子进程可能关闭打开父进程的文件和连接

vfork():

  • 用以创建进程,且不创建一个同样的内存映像,也称为轻量级fork()
  • 因为有copy on write技术出现,此技术用的较少

copy on write技术:

  • fork子进程时,子进程的地址空间没有真实复制父进程,仅复制了元数据(页表),指向与父进程相同的地址空间
  • 当父进程/子进程对某一个地址单元写时,会触发异常,将其操作的页复制为两份,使得父进程/子进程分别拥有不同的地址

c. 等待和终止进程

1) wait()系统调用

父进程用来等待子进程结束。一个子进程向父进程返回一个值,所以父进程必须接受这个值并处理,wait()系统调用被用于此功能

作用:

  • 使父进程睡眠来等待子进程的结果
  • 当一个子进程调用exit()时,操作系统解锁父进程,并通过exit()传递得到返回值作为wait调用的结果(连同子进程的pid一起),如果这里没有子进程存在,wait()立即返回
  • 父进程得到子进程pid后,会帮助释放子进程的内核资源(子进程PCB)

2) exit()系统调用

作用:

  • 将这个程序的结果作为参数返回
  • 关闭所有打开的文件,连接
  • 释放内存,释放大部分支持进程的操作系统结构
  • 检查父进程是否存活,如果是,则保留结果的值直到父进程需要它,进程没有真正死亡,但进入僵尸状态(不能转换为就绪态/等待态/运行态);如果没有,释放所有数据结构,进程死亡
  • root 进程会定期扫描僵尸进程,并清理

3) 六状态图(加了僵尸状态):

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值