前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《现代操作系统》—— 进程

《现代操作系统》—— 进程

原创
作者头像
VV木公子
修改2021-10-03 13:11:59
5510
修改2021-10-03 13:11:59
举报
文章被收录于专栏:TechBoxTechBox

前言

操作系统中最核心的概念就是进程。进程是对正在运行的程序的抽象。 没有进程的抽象,现代计算将不复存在。操作系统的其他所有内容都是围绕着进程的概念展开的。所以,透彻的理解进程是非常必要的。 进程是操作系统提供的最古老的、最重要的抽象概念之一。即使可以使用的CPU只有一个,但他们也具有支持(伪)并发操作的能力,他们将一个单独的CPU变换成多个虚拟的CPU。

进程

现代计算机经常会在同一时间做多个任务。比如,当系统启动时,会秘密启动许多进程,包括接收邮件的进程、病毒检测进程、文件打印进程等。这些进程所执行的活动都需要进行管理,于是一个支持多进程的多道程序设计系统就应运而生。与多道程序设计系统类似的是多处理器系统,但他们有本质的区别,下面会介绍。

多道程序设计系统:多道程序系统是在计算机内存中同时存放几道相互独立的程序,使它们在管理程序控制之下,相互穿插的运行。 两个或两个以上程序在计算机系统中同处于开始和结束之间的状态。这就称为多道程序技术运行的特征:多道、宏观上并发、微观上串行。

多道程序设计系统中多个程序的执行本质上是串行,也就是分时共享,因为处理器在多道程序间快速的切换,雨露均沾,达到了宏观上并发的效果。

多处理器系统: 多处理器系统(Multiprocessor Systems)是指包含两个或多个处理器,处理器之间彼此可以交换数据,所有处理器共享内存,I/O设备,控制器,及外部设备,整个硬件系统由统一的操作系统控制,在处理器和程序之间实现作业、任务、程序、数组极其元素各级的全面并行。

多处理器系统和多道程序设计系统区别

多处理器系统和多道程序设计系统的区别在于一个是硬件真并行,一个是软件伪并行。即前者因为存在多个CPU核心,实现了同一时间内多个相互独立程序在不同的CPU核心上同时执行,实现了真正的并发执行。后者因为是受系统调度的原因,在同一时间内只能有一个程序独享CPU,所以是一种伪并行。

我们了解了多道程序设计系统的伪并行,也了解了多处理器的真并行。因为人们很难对多个并行活动进行跟踪,所以经过多年努力,操作系统设计者研发了用于描述并行的一种概念模型——顺序进程。该模型是对系统中运行的程序的抽象,顺序进程使得并行更容易处理。有关该模型,正式本文的介绍重点。本文中,我们假设计算机只有一个CPU,即这个CPU是单核心的(虽然这种假设在现代计算机中几乎不存在)。

进程模型

在进程模型中,计算机上所有可运行的软件,通常也包括操作系统,被组织成若干个顺序进程(sequential process),简称进程

进程是对系统上正在运行的软件的抽象。一个进程就是一个正在执行程序的实例,包括程序计数器、寄存器和变量的当前值。笔者认为,它是一种动态的、非静止的概念,即运行中的程序,而非未运行的和停止运行的程序。

从概念上说,每个进程拥有它自己的虚拟CPU,当然实际上物理CPU在各进程之间来回切换。想象在一台多道程序计算机的内存中有4道程序,这4道程序被抽象为4个各自拥有自己控制流程(即拥有自己的逻辑程序计数器)的进程。且每个程序都独立运行。因实际上只有一个物理程序计数器,所以每个程序运行时,他的逻辑程序计数器被装载入物理程序计数器。当CPU暂停(或结束)执行该程序时,物理程序计数器又被保存到内存中该进程的逻辑程序计数器中。CPU就是这样不厌其烦的在多个程序间来回切换,以尽量达到公平公正,雨露均沾。

我们知道了,CPU在各进程之间来回快速切换,所以每个进程执行其运算你的速度是不确定的。而且当同一进程再次运行时,其运算速度通常也不可再现。所以,在对进程编程时绝不可对时序做任何想当然的假设。

一个进程是某种类型的一个活动,它有程序、输入、输出、状态。单个处理器可被若干个进程共享,它使用某种调度算法决定何时停止一个进程的工作,并转而为另一个进程提供服务。

进程和程序之间的区别微妙但很重要。比如,烘焙师就是CPU、烘焙蛋糕的食谱就是程序、烘焙师按照食谱执行一系列操作的总和就是进程。 烘焙师在烘焙蛋糕过程中被打断转而按照烹饪菜谱去炒菜就是进程的切换。烘焙师在转去炒菜之前需要先记录蛋糕做到了什么步骤,等待烹饪完之后再继续去烘焙蛋糕。这里,每个进程(烘焙蛋糕或炒菜)都有各自的程序(烘焙食谱或烹饪菜谱),而做蛋糕和炒菜的原料就是输入数据。记录的蛋糕的烘焙步骤就是状态。我们程序中,上下文的切换本质就是状态的保存和恢复。

如果一个程序运行了两遍,则算两个进程。例如,两次启动同一个程序或两个打印机同时打印一份文件。像这种两个进程运行一个程序,只有一份程序副本读入内存,两个进程共享一份只读代码,也不会改变两个进程正在运行的概念。

进程的创建

操作系统需要有一种方式来创建进程,或者说需要通过某种方式来创建进程。一些非常简单的系统,即只为运行一个程序而设计的系统,比如微波炉中的控制器,可能在系统启动时就创建了所有需要用到的进程。但对于通用系统,即我们通常用到的操作系统,因为其还要支持用户动态的启动、关闭一个程序,所以需要操作系统提供某种方法在运行时按需创建、撤销进程。所以对于通用系统而言,其创建进程的场景是多样的,主要包括以下4种事件:

  • 操作系统初始化创建进程
  • 进程通过系统调用创建新进程
  • 用户手动创建新进程
  • 初始化批处理作业创建新进程

操作系统初始化创建进程

操作系统启动时,通常会创建若干个进程。其中有些是前台进程,有些是后天进程。前台进程是指和用户(人类)交互并且替用户完成工作的进程。后台进程又叫做守护进程,它和特定用户没有直接关系,具有某些专门的功能。比如收发邮件、打印文件、定时提醒。在UNIX(此处理解为所有基于POSIX的系统,包括Linux、FreeBSD、macOS、Android、iOS、Solaris)中,可以用ps命令列出正在运行的进程。在Windows中,可以使用任务管理器查看。

进程通过系统调用创建新进程

除系统初始化创建进程之外,一个进程(运行中的程序)也可以在运行时通过发出系统调用来创建一个或多个新进程,以便协助前者完成工作。

用户手动创建新进程

在交互式系统中(比如UNIX、Windows),用户可以通过命令行键入一个命令或者双击一个图标就可以启动一个程序。这两种操作都会开启一个新的进程,并在新进程中运行所选择的程序。

初始化批处理作业创建新进程

这种创建进程的场景仅在大型机的批处理系统中应用。用户在这种系统中(可能是远程的)提交批处理作业,在操作系统发现有资源可运行另一个作业时,会创建一个新进程,然后运行其输入队列中的作业。

创建进程的命令

  • UNIX系统中只有一个系统调用来创建新进程:fork
  • Windows系统中的创建进程的系统调用是:CreateProcess

从技术上看,所有以上4种创建新进程的场景,新进程都是由一个已经存在的进程执行了一个用于创建进程的系统调用而创建的。后者可以是一个运行的用户进程、一个由键盘或鼠标启动的系统进程、一个批处理管理进程。系统调用通知操作系统创建一个新进程,并且直接或间接的指定在该进程中运行的程序。

通常,执行系统调用申请创建新进程的进程是父进程,被创建的新进程叫做子进程

关于父子进程的地址空间

子进程创建之后,父进程和子进程有各自不同的地址空间。即,如果其中某个进程在其地址空间修改了一个字,这个修改对其他进程是不可见的。在UNIX、Windows等系统中,子进程的初始地址空间是父进程的一个副本,即完全copy的父进程的地址空间,但这里涉及2个不同的地址空间。不可写的内存区是共享的,可写的内存区是不共享的。但对于一个新创建的进程而言,确实有可能共享其创建者的其他资源,比如一个在创建进程之前就打开的文件。除此之外,不同进程的地址空间中文件的共享通常分为两类:

  1. 不可写的内存区共享。
    • 父子进程拥有各自的地址空间。因为程序正文不能被修改,某些UNIX系统允许程序正文在两者间可共享。
  2. 内存通过写时复制共享。
    • 父子进程拥有各自的地址空间。但子进程仍可共享父进程的地址所有内存,这种情况下内存通过写时复制共享,写实复制意味着一旦两者之间想要修改这部分共享的内存,首先要对这块内存进行复制,把内容复制到自己的地址空间中,以确保修改发生在私有内存区域,即自己的地址空间。

综上,无论什么系统,无论如何,父子进程拥有各自的、独立的地址空间。更确切的说,每个进程都有各自的、独立的地址空间。可写的内存区是不可共享的。

进程的终止

进程有创建就有退出,进程开始的一刻就意味着将要结束,因为永恒是不存在的。继承的终止通常由以下4个条件引起:

  • 正常退出(自愿的)
    • 工作完成正常退出。UNIX中调用exit,Windows中调用ExitProcess
  • 出错退出(自愿的)
    • 进程发现了错误而退出。比如音语法错误编译器不能编译完成.c文件而退出
  • 严重错误退出(非自愿)
    • 程序内部错误导致的退出。比如执行了非法调用、引用了不存在的内存、发生除零操作。
    • 有些系统(如UNIX)中,进程可以通知操作系统自行处理某些类型的错误。在这些错误发生时,进程会收到系统发来的信号(被中断),即进程被系统的某个信号中断,进程得以知道发生了错误,而不是在这类错误发生时而异常退出。
  • 被其他进程杀死(非自愿)
    • 某个进程A执行一个系统调用(比如UNIX的kill)通知操作系统杀死某个其他进程B。
    • 在UNIX系统中,这个系统调用时kill;在Windows系统中,这个系统调用时TerminateProcess。
    • 执行kill或TerminateProcess的进程都必须获得确定的授权。

某些系统中,一个进程终止时,该进程所创建的进程都会被立即杀死。不过UNIX、Linux、Windows等我们常用的系统都不是这种工作方式。

进程的层次结构

UNIX系统中,父进程创建子进程之后,父子进程组成了一个父子节点的层次结构。子进程也可以继续创建它自己的子进程,这样父进程和子孙进程就形成了一个树形的层次结构。在UNIX中,进程和他的所有子进程以及后裔进程共同组成了一个进程组。当用户从键盘发出一个信号时,该信号被送给与键盘相关的进程组中的所有成员。即同一个组中的所有进程都可以收到这个键盘信号。每个进程都可以捕获、忽略该信号,或者采取默认动作——被该信号杀死。

WIndows系统中,不存在所谓的进程组的概念,所有的进程都是地位相同的。唯一类似于UNIX进程层次的地方是创建进程的时候,父进程得到一个特别的令牌——句柄,该句柄可以用来控制子进程,但父进程有权把令牌传送给其他进程。

进程的状态

进程有三种状态:

  • 运行态
    • 正在运行。该时刻当前进程占用CPU
  • 就绪态
    • 可随时运行。但因为其他进程正在zhanyongCPU而暂时停止,等待其他进程释放CPU
  • 阻塞态
    • 不能运行。即使CPU空闲,该进程也不能运行,除非某种外部事件发生

上图,进程的3中状态之间有4中可能的转换,分别如下:

  1. 进程因为等待输入而进入阻塞态
  2. 进程因为调度程序选择了另一个进程(使用CPU资源)而进入就绪态
  3. 进程因为被调度程序选中而进入运行态(使用CPU资源)
  4. 进程因为出现有效的输入而从阻塞态进入就绪态

而对于进程当前状态的下一个状态,笔者也做了总结,分别如下:

  • 当前为运行态
    • 下一个状态可以是阻塞态,即等待外部某个事件发生,比如用户输入
    • 下一个状态可以是就绪态,即调度程序把CPU资源分给了另一个进程
  • 当前为就绪态
    • 下一个状态只能是运行态,即等待调度程序把CPU资源分给自己
  • 当前为阻塞态
    • 下一个状态只能是就绪态,即外部事件发生后转入就绪态,等待CPU资源

我们已经知道,进程模型是对正在运行的程序的抽象,使用进程模型使我们易于想象系统内部的操作状态。从进程模型的状态转换可以知道,操作系统需要根据某些规则进行进程的切换调度,比如在进程A等待用户输入时,操作系统可以让CPU转而处理进程B的任务,以达到CPU的最大利用率。所以,操作系统的最底层是调度程序,在调度程序之上有很多进程。所有关于中断处理、启动进程、停止进程的具体细节都隐藏再调度程序中。实际上,调度程序是一段非常短小的程序。理想的实现方式是,操作系统的其他部分被简单的组织成进程的形式,运行在调度程序之上,但很少有真实的系统是这样实现的。如下图所示,是一个调度程序和进程的简易关系图。

进程的实现

为了实现进程模型,操作系统维护这一张表格(一个结构数组),即进程表(process table)。每个进程占用一个进程表项,进程表项即代表了一个进程。该表项包含了进程状态的重要信息,包括:程序计数器(PC)、堆栈指针(FP、SP)、内存分配状态、打开的文件的状态、账号、调度信息,以及其他在进程由运行态转到就绪态或阻塞态时必须要保存的信息,从而保证进程随后能再次启动,就像从未被中断过一样。

多道程序设计模型

我们已经知道,多道程序设计系统的特点是:

  • 内存中同时存在多道相互独立的进程
  • 宏观上并行
  • 微观上串行

这样的特点也带来了多道程序设计模型的优点:可以提高CPU的利用率,减少CPU的空转等待时间。 严格的说,如果进程用于计算的平局时间是进程在内存中停留时间得20%,且内存中同时有5个进程,则CPU将一直满负载运行。然而这个模型在现实中过于乐观,因为他假设这5个进程不会同时等待I/O,这种假设本身就是不成立的。

更好的模型是从概率上来看CPU的利用率。假设一个进程等待I/O操作的时间与其停留在内存中的时间比为p.当内存中同时又n个进程时,则所有的n个进程都在等待I/O的概率是p^npn(都在等待I/O即代表CPU此时在空转)。CPU的利用率的公式如下:

CPU利用率 = 1 - p^npn

至此,进程这个概念就介绍完了,下一篇文章将会介绍线程这个概念。

文/VV木公子(原创作者)

PS:如非特别说明,所有文章均为原创作品,著作权归作者所有,转载请联系作者获得授权,并注明出处!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 进程
    • 进程模型
      • 进程的创建
        • 操作系统初始化创建进程
        • 进程通过系统调用创建新进程
        • 用户手动创建新进程
        • 初始化批处理作业创建新进程
      • 创建进程的命令
        • 关于父子进程的地址空间
      • 进程的终止
        • 进程的层次结构
          • 进程的状态
            • 进程的实现
            • 多道程序设计模型
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档