进程和线程详解

进程:运行中的程序

一次执行一个程序效率慢,比如有一个会读取硬盘文件数据的程序被执行了,那么当运行到读取文件的指令时,就会去从硬盘读取数据,但是硬盘的读写速度是非常慢的,这时如果 CPU 等着硬盘返回数据的话, CPU 的利用率非常低。

故引入多个程序、交替执行的思想,CPU 会从一个进程快速切换至另一个进程,其间每个进程各运行几十或几百个毫秒。这会产生并行的错觉,其实这是并发。

并发是一个处理器交替执行多个任务。

并行是两个处理器分别执行两个任务。

进程的状态

  • 运行状态(Runing):该时刻进程占用 CPU;
  • 就绪状态(Ready):可运行,但因为其他进程正在运行而暂停停止;
  • 阻塞状态(Blocked):该进程正在等待某一事件发生(如等待输入/输出操作的完成)而暂时停止运行,这时,即使给它CPU控制权,它也无法运行;
  • 创建状态(new):进程正在被创建时的状态;
  • 结束状态(Exit):进程正在从系统中消失时的状态

上面的状态都好理解,而挂起状态是什么?为什么会有挂起状态?

假设有大量处于阻塞状态的进程,进程可能会占用大量物理内存空间,被阻塞状态的进程占用着物理内存就一种浪费物理内存的行为。故在虚拟内存管理的操作系统中,通常会把阻塞状态的进程的物理内存空间换出到硬盘,等需要再次运行的时候,再从硬盘换入到物理内存。故这种描述进程没有占用实际的物理内存空间的情况,这个状态就是挂起状态

挂起状态可以分为两种:

  • 阻塞挂起状态:进程在外存(硬盘)并等待某个事件的出现;
  • 就绪挂起状态:进程在外存(硬盘),但只要进入内存,即刻立刻运行

进程的控制结构 

操作系统用进程控制块process control block,PCB)数据结构来描述进程。

PCB 包含的主要信息如下:

  1. 进程标识符(Process ID, PID):用于唯一标识一个进程。
  2. 进程状态(Process State):表示当前进程的状态,例如就绪、运行、等待、挂起等。
  3. 程序计数器(Program Counter, PC):用于记录程序当前执行的位置,即下一条指令的地址。
  4. CPU 寄存器(CPU Register):包含了 CPU 中各个寄存器的值,包括通用寄存器、程序计数器和栈指针等。
  5. 进程优先级(Process Priority):用于记录进程的优先级,以便操作系统进行进程调度。
  6. 进程拥有者(Process Owner):表示进程的拥有者,通常是创建该进程的用户。
  7. 进程所属组(Process Group):表示进程所属的组,通常是创建该进程的用户所在的组。
  8. 内存管理信息(Memory Management Information):用于记录进程占用的内存地址空间信息,包括进程的代码段、数据段、堆栈等。
  9. 文件描述符(File Descriptor):用于记录进程打开的文件,包括文件的类型、位置和权限等信息。
  10. 进程间通信信息(Interprocess Communication, IPC):用于记录进程与其他进程进行通信的方式,例如共享内存、消息队列、管道等。

相同状态的进程通常是以链表方式组成各种队列。因为可能会面临进程创建,销毁等调度导致进程状态发生变化,链表能够更加灵活的插入和删除。

进程的控制

进程的创建

分配进程唯一标识符;申请一个空白的 PCB;为进程分配资源;初始化 PCB;将进程插入到就绪队列,等待被调度运行。

其中可能会遇到申请PCB失败、分配资源失败等问题。

进程的终止

 查找要终止 进程的PCB;若该进程处于执行状态则终止进程执行并将CPU资源分配给其他进程;终止其所有子进程;归还所有资源给父进程或操作系统;将PCB从所在队列删除。

进程的阻塞

找到PCB;若该进程为运行状态则保护其现场,将其状态转为阻塞状态,停止运行;将该 PCB 插入的阻塞队列中去

进程的唤醒

找到PCB;将该进程从阻塞队列中移去并将状态转为就绪状态 ;将PCB插入到就绪队列

进程的上下文切换

各个进程之间共享 CPU 资源,在不同的时候进程之间需要切换,一个进程切换到另一个进程运行,称为进程的上下文切换

CPU 上下文:CPU在执行程序时,保存当前状态信息的一组寄存器值和其他相关信息的集合。它是实现任务切换和中断处理的关键机制之一。CPU上下文信息包括:

  1. 程序计数器的值,用于存储下一条指令的地址。
  2. 栈指针的位置,用于指向堆栈中的当前位置。
  3. 寄存器的值,例如累加器和指针寄存器等。
  4. 状态寄存器的值,用于表示CPU的状态信息,例如运算结果是否为零,是否有进位等。
  5. 其他处理器特定的状态信息,例如标志寄存器等。

CPU 上下文切换就是先把前一个任务的 CPU 上下文保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。

由于进程是由内核管理和调度的,所以进程的切换只能发生在内核态进程的上下文切换不仅包含了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的资源。

进程上下文切换过程:

  1. 操作系统决定要切换到哪个进程。操作系统使用进程调度算法来选择下一个要执行的进程。
  2. 保存当前进程的上下文信息。进程切换前需要将当前进程的CPU上下文信息保存到内存中。
  3. 加载下一个进程的上下文信息。在进行进程切换时,需要从内存中加载下一个进程的CPU上下文信息,以恢复该进程的执行状态。
  4. 更新进程控制块(PCB)。更新当前进程的状态,同时将下一个进程的PCB加载到内存中。
  5. 恢复下一个进程的执行。在完成上述步骤后,操作系统将CPU控制权转移到下一个进程,从下一个进程的程序计数器处开始执行
  6. 进程执行。当下一个进程被执行时,操作系统会根据进程调度算法的规则在各个进程之间进行切换。上述步骤将重复执行,直到所有进程都执行完毕。

通常,会把交换的信息保存在进程的 PCB,当要运行另外一个进程的时候,我们需要从这个进程的 PCB 取出上下文,然后恢复到 CPU 中,这使得这个进程可以继续执行。

线程

 线程是进程当中的一条执行流程。

线程与进程最大的区别在于:线程是调度的基本单位,而进程则是资源拥有的基本单位

为什么引入线程:

由于进程是资源的拥有者,所以在创建、撤销、切换操作中需要较大的时空开销,限制了并发程度的进一步提高。为减少进程切换的开销,把进程作为资源分配单位和调度单位这两个属性分开处理,即进程还是作为资源分配的基本单位,但是不作为调度的基本单位(很少调度或切换),把调度执行与切换的责任交给“线程”。这样做的好处不但可以提高系统的并发度,还能适应新的对称多处理机(SMP)环境的运行,充分发挥其性能。

每个线程都有独立一套的寄存器和栈,这样可以确保线程的控制流是相对独立的。

线程与进程的比较:

  • 进程是资源(包括内存、打开的文件等)分配的单位,线程是 CPU 调度的单位;
  • 进程拥有一个完整的资源平台,而线程只独享必不可少的资源,如寄存器和栈;
  • 线程同样具有就绪、阻塞、执行三种基本状态,同样具有状态之间的转换关系;
  • 线程能减少并发执行的时间和空间开销;

线程相比进程能减少开销,体现在

线程的创建时间比进程快,因为进程在创建的过程中,还需要资源管理信息,比如内存管理信息、文件管理信息,而线程在创建的过程中,不会涉及这些资源管理信息,而是共享它们;
线程的终止时间比进程快,因为线程释放的资源相比进程少很多;
同一个进程内的线程切换比进程切换快,因为线程具有相同的地址空间(虚拟内存共享),这意味着同一个进程的线程都具有同一个页表,那么在切换的时候不需要切换页表。而对于进程之间的切换,切换的时候要把页表给切换掉,而页表的切换过程开销是比较大的;
由于同一进程的各线程间共享内存和文件资源,那么在线程之间数据传递的时候,就不需要经过内核了,这就使得线程之间的数据交互效率更高了;
所以,线程比进程不管是时间效率,还是空间效率都要高。

线程的实现

图1. 用户级线程和内核级线程

用户级线程(User-Level Thread, ULT):

多对一模型。将多个用户级线程映射到一个内核级线程。所有工作都由应用程序在用户空间中完成,内核意识不到线程的存在。应用程序可以通过使用线程库设计多线程程序。如上图(a)。对于设置了用户级线程的系统,其调度仍以进程为单位进行。

 用户级线程的优点:

1. 线程切换不需要切换到内核空间,而是由线程库函数来完成,节省了模式切换的开销。

2. 调度算法是进程专用的,不同的进程可根据需要对自己的线程选择不同的调度算法。

3. 用户级线程的实现与操作系统平台无关,对线程管理的代码是属于用户程序的一部分。

用户级线程缺点:

1. 系统调用的阻塞问题。当线程执行一个系统调用时,不仅该线程被阻塞,进程内所有线程都被阻塞。

2. 不能发挥多处理机优势。内核每次分配给一个进程的仅有一个CPU,因为进程中仅有一个线程能执行。

内核级线程(Kernel-Level Thread, KLT):

一对一模型。将每个用户级线程映射到一个内核级线程。内核级线程管理的所有工作在内核空间内实现。内核空间为每个内核级线程设置一个线程控制块,内核根据该控制块感知某线程的存在并加以控制。如图1(b)。

内核级线程优点:

1. 能发挥多处理机优势。内核能同时调度同一进程中的多个线程并行执行。

2. 如果进程中的一个线程被阻塞,内核可以调度该进程中的其他线程占用处理机,也可运行其他进程中的线程。

3. 内核支持线程具有很小的数据结构和堆栈,线程切换比较快,开销小。

4. 内核本身也可采用多线程技术,提高系统的执行速度和效率。

内核级线程缺点:

同一进程中的线程切换,需要从用户态转到核心态进行,系统开销大。这是因为用户进程的线程在用户态运行,而线程调度和管理是在内核实现

组合模式

如图1(c)。综合了前两种优点,大部分的线程上下文发生在用户空间,且多个线程又可以充分利用多核 CPU 的资源。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值