【操作系统—虚拟化】进程

概念

进程的非正式定义非常简单:进程就是运行中的程序。程序本身是没有生命周期的,它只是存在磁盘上面的一些指令(也可能是一些静态数据)。人们常常希望同时运行多个程序,一个正常的系统可能会有上百个进程同时在运行。

操作系统通过虚拟化(virtualizing)CPU来提供这种假象。通过让一个进程只运行一个时间片,然后切换到其他进程,操作系统提供了存在多个虚拟CPU的假象。这就是时分共享(time sharing)CPU技术,允许用户如愿运行多个并发进程。潜在的开销就是性能损失,因为如果CPU必须共享,每个进程的运行就会慢一点。

抽象:进程

操作系统为正在运行的程序提供的抽象,就是所谓的进程(process)。正如我们上面所说的,一个进程只是一个正在运行的程序。在任何时刻,我们都可以清点它在执行过程中访问或影响的系统的不同部分,从而概括一个进程。

为了理解构成进程的是什么,我们必须理解它的机器状态(machine state):程序在运行时可以读取或更新的内容。进程的机器状态有一个明显组成部分,就是它的内存。指令存在内存中,正在运行的程序读取和写入的数据也在内存中。因此进程可以访问的内存(称为地址空间,address space)是该进程的一部分。

进程的机器状态的另一部分是寄存器。许多指令明确地读取或更新寄存器,因此,它们对于执行该进程很重要。例如,程序计数器(ProgramCounter,PC)(有时称为指令指针,Instruction Pointer或IP)告诉我们程序当前正在执行哪个指令;类似地,栈指针(stack pointer)和相关的帧指针(frame pointer)用于管理函数参数栈、局部变量和返回地址。

最后,程序也经常访问持久存储设备。此类I/O信息可能包含当前打开的文件列表。

进程创建

操作系统运行程序必须做的第一件事是将代码和所有静态数据(例如初始化变量)加载(load)到内存中,也即加载到进程的地址空间中。程序最初以某种可执行格式驻留在磁盘上。因此,将程序和静态数据加载到内存中的过程,需要操作系统从磁盘读取这些字节,并将它们放在内存中的某处。

将代码和静态数据加载到内存后,操作系统在运行此进程之前还需要执行其他一些操作。必须为程序的运行时栈(run-time stack或stack)分配一些内存

操作系统也可能为程序的堆(heap)分配一些内存。在C程序中,堆用于显式请求的动态分配数据。程序通过调用malloc()来请求这样的空间,并通过调用free()来明确地释放它。

操作系统还将执行一些其他初始化任务,特别是与输入/输出(I/O)相关的任务。例如,在UNIX系统中,默认情况下每个进程都有3个打开的文件描述符(file descriptor),用于标准输入、输出和错误。

通过将代码和静态数据加载到内存中,通过创建和初始化栈以及执行与I/O设置相关的其他工作,OS现在为程序执行搭好了舞台。然后它有最后一项任务:启动程序,在入口处运行,即main()。通过跳转到main()例程,OS将CPU的控制权转移到新创建的进程中,从而程序开始执行。

进程状态

简而言之,进程可以处于以下3种(稳定)状态之一。

  • 运行(running):在运行状态下,进程正在处理器上运行。这意味着它正在执行指令。
  • 就绪(ready):在就绪状态下,进程已准备好运行,但由于某种原因,操作系统选择不在此时运行。
  • 阻塞(blocked):在阻塞状态下,一个进程执行了某种操作,直到发生其他事件时才会准备运行。一个常见的例子是,当进程向磁盘发起I/O请求时,它会被阻塞,因此其他进程可以使用处理器。

数据结构

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

操作系统追踪进程的一些重要信息。对于停止的进程,寄存器上下文将保存其寄存器的内容。当一个进程停止时,它的寄存器将被保存到这个内存位置。通过恢复这些寄存器(将它们的值放回实际的物理寄存器中),操作系统可以恢复运行该进程。

除了运行、就绪和阻塞之外,还有其他一些进程可以处于的状态。有时候系统会有一个初始(initial)状态,表示进程在创建时处于的状态。另外,一个进程可以处于已退出但尚未清理的最终(final)状态(在基于UNIX的系统中,这称为僵尸状态)。

注:存储关于进程的信息的个体结构称为进程控制块(Process Control Block,PCB)。

你可能感兴趣的:(操作系统)