CPU虚拟化-进程
2023-1-9
| 2023-8-2
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password
Property
 
程序本身是没有生命周期的,只是存在磁盘上面的一些指令(也可能是一些静态数据)。是操作系统让这些字节运行起来,让程序发挥作用。
 
人们常常希望同时运行多个程序,虽然只有少量的物理CPU可用,但是操作系统如何提供几乎有无数个的CPU可用的假象?
操作系统通过虚拟化CPU 来提供这种假象。通过让一个进程只运行一个时间片,然后切换到其他进程,操作系统提供了存在多个虚拟CPU 的假象。这就是时分共享CPU 技术,允许用户如愿运行多个并发进程。潜在的开销就是性能损失,因为如果CPU 必须共享,每个进程的运行就会慢一点。
 
  • 时分共享(time sharing)是操作系统共享资源所使用的最基本的技术之一。通过允许资源由一个实体使用一小段时间,然后由另一个实体使用一小段时间,如此下去,所谓的资源(例如,CPU 或网络链接)可以被许多人共享。
  • 时分共享的自然对应技术是空分共享,资源在空间上被划分给希望使用它的人。例如,磁盘空间自然是一个空分共享资源,因为一旦将块分配给文件,在用户删除文件之前,不可能将它分配给其他文件。
 
 

抽象:进程

操作系统为正在运行的程序提供的抽象,就是所谓的进程(process)。在任何时刻,我们都可以清点它在执行过程中访问或影响的系统的不同部分,从而概括一个进程。
为了理解构成进程的是什么,我们必须理解它的机器状态(machine state):程序在运行时可以读取或更新的内容。
  • 进程的机器状态有一个明显组成部分,就是它的内存。指令存在内存中。正在运行的程序读取和写入的数据也在内存中。因此进程可以访问的内存(地址空间)是该进程的一部分。
  • 进程的机器状态的另一部分是寄存器。许多指令明确地读取或更新寄存器,因此显然,它们对于执行该进程很重要。 注:有一些非常特殊的寄存器构成了该机器状态的一部分,例如,程序计数器(Program Counter,PC)(有时称为指令指针,Instruction Pointer 或IP)告诉我们程序当前正在执行哪个指令;栈指针(stack pointer)和相关的帧指针(frame pointer)用于管理函数参数栈、局部变量和返回地址。
 
 
操作系统使用进程列表记录当前的所有进程,进程列表由一系列进程控制块(PCB)组成(可以是数组或者双向链表等),进程的相关属性信息存储在进程控制块中,典型的进程属性信息包括:PID、状态、地址空间、硬件状态等。
  • PID:进程的标识符,除了本身的PID以外,还应当记录parent PID
  • State:进程状态
  • Address space:进程的虚拟内存地址空间,包括主存(用户空间、内核空间)、寄存器(一般寄存器、控制寄存器)、外部设备(文件、socket、其他内存映射IO设备)等
  • Hardware state:特指关键的寄存器如PC、SP等
 
 

进程API

  • 创建(create):操作系统必须包含一些创建新进程的方法。在shell 中键入命令或双击应用程序图标时,会调用操作系统来创建新进程,运行指定的程序。
    •  
      程序如何转化为进程? 进程创建实际如何进行?
      notion image
      操作系统运行程序必须做的第一件事是将代码和所有静态数据(如初始化变量)加载到内存中,加载到进程的地址空间中。程序最初以某种可执行格式驻留在磁盘上。将程序和静态数据加载到内存中的过程,需要操作系统从磁盘读取这些字节,并将它们放在内存中的某处。
    • 早期的(简单的)操作系统中,加载过程尽早完成,即在运行程序之前全部完成
    • 现代操作系统惰性执行该过程,即仅在程序执行期间需要加载的代码或数据片段,才会加载
    •  
      将代码和数据加载到内存后,操作系统在运行此进程之前还需要执行一些其他的操作,必须为程序的运行时栈(run-time stack 或stack)分配一些内存。c程序使用存放局部变量、函数参数和返回地址。操作系统分配这些内存,并提供给进程。操作系统也有可能会用参数初始化栈。具体来说,它会将参数填入main()函数,即argcargv数组。
      操作系统也可能为程序的分配一些内存。在c程序中,堆用于显示请求的动态分配数据,通过malloc/free函数申请给数据结构(链表、散列表、树等)的内存。
      操作系统还将执行一些其他初始化任务,特别是输入输出相关的。例如,Unix系统中,默认情况下每个进程都有三个打开的文件描述符,用于标准输入、输出和错误。
      以上任务完成后,启动程序,在入口处运行,即main()。通过跳转到main()例程,OS将CPU的控制权转移到新创建的进程中,从而开始执行程序。
       
  • 销毁(destroy):由于存在创建进程的接口,因此系统还提供了一个强制销毁进程的接口。当然,很多进程会在运行完成后自行退出。但是,如果它们不退出,用户可能希望终止它们,因此停止失控进程的接口非常有用。
  • 等待(wait):有时等待进程停止运行是有用的,因此经常提供某种等待接口。
  • 其他控制(miscellaneous control):除了杀死或等待进程外,有时还可能有其他控制。例如,大多数操作系统提供某种方法来暂停进程(停止运行一段时间),然后恢复(继续运行)。
  • 状态(statu):通常也有一些接口可以获得有关进程的状态信息,例如运行了多长时间,或者处于什么状态。
 
 
unix中关于进程的API有:
  • fork():复制出与当前进程一样的子进程,当前进程与子进程同时运行(按照调度规则),根据fork对当前进程与子进程的返回值不一样(父进程中,返回新创建子进程的进程ID;在子进程中,返回0),(按照返回值作为判断依据的分支)执行不同的程序片段直到返回。
    • notion image
  • wait():在使用了fork已经创建了子进程的情况下, 当前进程执行到wait处时等待子进程返回后才接着运行。
    • notion image
  • exec():使用exec后,新的进程将直接替代当前进程(而不是创建子进程的并结束当前进程),新进程覆盖原来的内存空间(例如数据段、代码段、栈等)并接着运行直到返回。exec()有几种变体:execl()execle()execlp()execv()execvp()
    • notion image
  • kill():向进程发送一个信号(包括要求进程睡眠、终止或其他指令)。
 
 
 
 
 

进程状态

进程可以处于以下三种状态之一:
  • 运行(running):在运行状态下,进程正在处理器上运行。这意味着它正在执行指令。
  • 就绪(ready):在就绪状态下,进程已准备好运行,但由于某种原因,操作系统选择不在此时运行。
  • 阻塞(blocked):在阻塞状态下,一个进程执行了某种操作,直到发生其他事件时才会准备运行。一个常见的例子是,当进程向磁盘发起I/O请求时,它会被阻塞,因此其他进程可以使用处理器。
 
可以根据操作系统的载量,让进程在就绪状态和运行状态之间转换。从就绪到运行意味着该进程已经被调度(scheduled)。从运行转移到就绪意味着该进程已经取消调度(descheduled)。一旦进程被阻塞(例如,通过发起I/O 操作),OS 将保持进程的这种状态,直到发生某种事件(如,I/O完成)。此时,进程再次转入就绪状态(也可能立即再次运行,如果操作系统这样决定)。
notion image
notion image
 
notion image
Process0发起I/O并被阻塞,等待I/O完成。如,当从磁盘读取数据或等待网络数据包时,进程会被阻塞。OS发现Process0 不使用CPU 并开始运行Process1。当Process1运行时,I/O完成,将Process0移回就绪状态。最后,Process1结束,Process0 运行,然后完成
注:操作系统必须做出许多决定。首先,系统必须决定在Process0发出I/O 时运行Process1。这样做可以通过保持CPU 繁忙来提高资源利用率。其次,当I/O完成,系统决定不切换回Process0。目前还不清楚这是不是一个很好的决定,这些类型的决策由操作系统调度程序完成。
 
 

数据结构

操作系统是一个程序,和其他程序一样,它有一些关键的数据结构来跟踪各种相关的信息。例如,为了跟踪每个进程的状态,操作系统可能会为所有就绪的进程保留某种进程列表(process list),以及跟踪当前正在运行的进程的一些附加信息。操作系统还必须以某种方式跟踪被阻塞的进程。当I/O 事件完成时,操作系统应确保唤醒正确的进程,让它准备好再次运行。
 
  • 计算机基础
  • 操作系统
  • 操作系统介绍CPU虚拟化-机制:受限直接执行
    目录