【操作系统】基础知识整理 & 常见面试题

最后都变了- 提交于 2019-11-29 19:06:45

1 操作系统概述

  操作系统是管理和控制计算机系统中各种硬件和软件资源、合理地组织计算机工作流程的系统软件,是用户与计算机之间的接口。

操作系统的四个特性

  1. 并发:同一段时间内多个程序执行(注意区别并行和并发,前者是同一时刻的多个事件,后者是同一时间段内的多个事件);
  2. 共享:系统中的资源可以被内存中多个并发执行的进线程共同使用;
  3. 虚拟:通过时分复用(如分时系统)以及空分复用(如虚拟内存)技术实现把一个物理实体虚拟为多个;
  4. 异步:系统中的进程是以走走停停的方式执行的,且以一种不可预知的速度推进。

  操作系统最基本的特征是并发和共享,两者互为存在条件。

操作系统的五大功能

  1. 处理机管理:处理机分配都是以进程为单位,所以处理机管理也被看做是进程管理。包括进程控制,进程同步,进程通信和调度(作业调度和进程调度)
  2. 存储器管理(或者内存管理):内存分配,内存保护,地址映射,内存扩充
  3. 设备管理:管理所有外围设备,包括完成用户的IO请求;为用户进程分配IO设备;提高IO设备利用率;提高IO速度;方便IO的使用
  4. 文件管理:管理用户文件和系统文件,方便使用同时保证安全性。包括:文件存储空间管理,目录管理,文件读写管理以及文件共享和保护
  5. 提供用户接口:程序接口(如API)和用户接口(如GUI)

2 进程

进程的定义

  进程:指在系统中能独立运行并作为资源分配的基本单位,它是由一组机器指令、数据和堆栈等组成的,是一个能独立运行的活动实体。
进程只能由父进程建立,系统中所有的进程形成一种进程树的层次体系;挂起命令可由进程自己和其他进程发出,但是解除挂起命令只能由其他进程发出。

进程的状态

在这里插入图片描述

  • 创建状态:进程在创建时需要申请一个空白PCB,向其中填写控制和管理进程的信息,完成资源分配。如果创建工作无法完成,比如资源无法满足,就无法被调度运行,把此时进程所处状态称为创建状态
  • 就绪状态:进程已经准备好,已分配到所需资源,只要分配到CPU就能够立即运行
  • 执行状态:进程处于就绪状态被调度后,进程进入执行状态
  • 阻塞状态:正在执行的进程由于某些事件(I/O请求,申请缓存区失败)而暂时无法运行,进程受到阻塞。在满足请求时进入就绪状态等待系统调用
  • 终止状态:进程结束,或出现错误,或被系统终止,进入终止状态。无法再执行

进程的特性

  1. 动态性:进程的实质是程序的一次执行过程,进程是动态产生,动态消亡的。
  2. 并发性:任何进程都可以同其他进程一起并发执行。
  3. 独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位。
  4. 异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进。

进程的同步、互斥和通信

参考:进程的同步、互斥、通信的区别,进程与线程同步的区别
  进程的互斥、同步都是在并发进程下存在的概念。有了并发进程,就会产生资源的竞争与协作,则这些进程之间存在两种基本关系:竞争关系协作关系

  • 为了解决进程间竞争关系(间接制约关系)引入进程互斥
  • 为了解决进程间松散的协作关系(直接制约关系)引入进程同步
  • 为了解决进程间紧密的协作关系引入进程通信

a 竞争关系 和 进程互斥

  由于创建了多个进程,这些进程共享计算机的资源。而对于一些独占型(就是同一时刻只能有一个进程在占有这些资源)的资源,则会引发进程之间的竞争。
  资源竞争出现两种控制问题:死锁和饥饿

  1. 死锁:是指两个或两个以上的进程(或线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
    Java中产生死锁的最根本原因是: 一、是多个线程涉及到多个锁,这些所存在着交叉,所以可能会导致了一个锁以来的闭环;二、默认的锁申请操作是阻塞的。例如:进程在获得一个锁L1的情况下再去申请另外一个锁L2,即L2想要包含L2。在获得了L1,且没有释放L1的情况下又去申请L2,这是产生死锁的最根本原因。
    死锁产生的四个必要条件:
    互斥条件:进程对于所分配到的资源具有排它性,即一个资源只能被一个进程占用,直到被该进程释放
    请求和保持条件:一个进程因请求被占用资源而发生阻塞时,对已获得的资源保持不放。
    不剥夺条件:任何一个资源在没被该进程释放之前,任何其他进程都无法对他剥夺占用
    循环等待条件:当发生死锁时,所等待的进程必定会形成一个环路(类似于死循环),造成永久阻塞。
    避免死锁的三种技术:
    加锁顺序(线程按照一定的顺序加锁):如果能确保所有的线程都是按照相同的顺序获得锁,那么死锁就不会发生。
    加锁时限:在尝试获取锁的时候加一个超时时间,这也就意味着在尝试获取锁的过程中若超过了这个时限该线程则放弃对该锁请求。若一个线程没有在给定的时限内成功获得所有需要的锁,则会进行回退并释放所有已经获得的锁,然后等待一段随机的时间再重试。这段随机的等待时间让其它线程有机会尝试获取相同的这些锁,并且让该应用在没有获得锁的时候可以继续运行
    死锁检测:主要是针对那些不可能实现按序加锁并且锁超时也不可行的场景。每当一个线程获得了锁,会在线程和锁相关的数据结构中将其记下。除此之外,每当有线程请求锁,也需要记录在这个数据结构中。当一个线程请求锁失败时,这个线程可以遍历锁的关系图看看是否有死锁发生。
  2. 饥饿:指这样一种情况——一个进程由于其他进程总是优先于它而被无限期拖延。

  操作系统需要保证诸进程能互斥地访问临界资源,既要解决饥饿问题,又要解决死锁问题。
  进程的互斥(mutual exclusion)是解决进程间竞争关系( 间接制约关系) 的手段。 进程互斥指若干个进程要使用同一共享资源时,任何时刻最多允许一个进程去使用,其他要使用该资源的进程必须等待,直到占有资源的进程释放该资源。

b 协作关系 和 进程同步

  某些进程为完成同一任务需要分工协作,由于合作的每一个进程都是独立地以不可预知的速度推进,这就需要相互协作的进程在某些协调点上协 调各自的工作。当合作进程中的一个到达协调点后,在尚未得到其伙伴进程发来的消息或信号之前应阻塞自己,直到其他合作进程发来协调信号或消息后方被唤醒并继续执行。
  这种协作进程之间相互等待对方消息或信号的协调关系称为进程同步
  允许进程协同工作有利于共享信息、有利于加快计算速度、有利于实现模块化程序设计。进程的同步(Synchronization)是解决进程间协作关系( 直接制约关系) 的手段
  Linux下进程间的同步方式有:(对比线程的同步方式

  • 信号量
      信号量是为了控制一个具有有限先数量用户资源而设计的。他允许多个线程在同一时刻访问统一资源,但是需要限制在同一时刻访问此资源的最大线程数目。
    【互斥量是信号量的一种特殊情况,当信号量的最大资源数=1就是互斥量了。】
    优点:适用于Socket(套接字)程序中进程的同步;
    缺点:①信号量机制必须有公共内存,不能用于分布式操作系统(最大缺点);
       ②信号量机制功能强大,但使用时对信号量的操作分散,而且难以控制,读写和维护都很困难,加重了程序员的代码负担;
       ③核心操作P-V分散在各用户程序的代码中,不易控制和管理,一旦错误,后果严重,且不易发现和纠正。

  • 管程

  • 互斥量(基于共享内存的快速用户态)

  • 文件锁(通过fcntl设定,针对文件)

c 进程通信

  并发进程之间的交互必须满足两个基本要求:同步和通信。
  进程竞争资源时要实施互斥,互斥是一种特殊的同步,实质上需要解决好进程同步问题,进程同步是一种进程通信,通过修改信号量,进程之间可建立起联系,相互协调运行和协同工作。
进程间的通信方式:

  • 1、无名管道通信:数据只能单向移动,只能在具有亲缘的进程间使用;
  • 2、高级管道通信:将另一个程序当作一个新的进程在当前程序中启动,则这个程序是当前进程的子进程;
  • 3、有名管道通信:允许无亲缘关系进程间的通信;
  • 4、消息队列通信:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识,消息队列克服了消息传递消息少等特点;
  • 5、信号量通信:信号量用于控制多个进程对共享资源的访问;
  • 6、信号通信:用于接受进程某个事件已经发生;
  • 7、共享内存通信:共享内存映射一段能被其他进程所访问的内存,往往与其他通信机制配合使用,来实现进程间的同步和通信;
  • 8、套接字通信:用于不同机器之间的进程通信。

3 线程

线程的定义

  线程:线程是进程中的一个实体,作为系统调度和分派的基本单位。

线程的性质

  1. 线程是进程内的一个相对独立的可执行的单元。若把进程称为任务的话,那么线程则是应用中的一个子任务的执行。
  2. 由于线程是被调度的基本单元,而进程不是调度单元。所以,每个进程在创建时,至少需要同时为该进程创建一个线程。即进程中至少要有一个或一个以上的线程,否则该进程无法被调度执行。
  3. 进程是被分给并拥有资源的基本单元。同一进程内的多个线程共享该进程的资源,但线程并不拥有资源,只是使用他们。
  4. 线程是操作系统中基本调度单元,因此线程中应包含有调度所需要的必要信息,且在生命周期中有状态的变化。
  5. 由于共享资源(包括数据和文件),所以线程间需要通信和同步机制,且需要时线程可以创建其他线程,但线程间不存在父子关系。

线程通信

参考:深入理解线程通信
线程通信的方式有:

  • 等待通知机制
    是 Java 中比较经典的线程通信方式,两个线程通过对同一对象调用等待 wait() 和通知 notify() 方法来进行通讯。
  • join() 方法
  • volatile 共享内存
  • CountDownLatch 并发工具
    CountDownLatch 可以实现 join 相同的功能,但是更加的灵活。
  • CyclicBarrier 并发工具
  • 线程响应中断
  • 线程池 awaitTermination() 方法
  • 管道通信

线程同步和互斥

  当有多个线程的时候,经常需要去同步这些线程一访问同一个数据或资源。
  例如,假设有一个程序,其中一个线程用于把文件读到内存,而另个线程用于统计文件的字符数,两个不同的操作有自己各自的线程,操作系统会把两个线程当作是互补相干的任务分别执行。但是在整个文件调入内存之前,统计字符数是没有意义的。为了防止该事件的发生,必须是两个线程同步工作。
互斥
  互斥是指分布在不同进程之间的若干程序片段,当某个进程运行其中有一个程序片段时,其它进程就不能运行它们其中的任一程序片段,只能等到该进程运行完这个程序片段后才可以运行。
  如果用对资源的访问来定义的话,互斥是指某一资源同时只允许一个访问者对其进行访问,具有唯一性排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。

同步
  同步指散布在不同进程之间的若干程序片段,它们的运行必须严格按照规定某种先后次序来运行,这种先后次序依赖于要完成的特定任务。
  如果用资源的访问来定义的话,同步是指在互斥的基础上(大多数情况),通过其他机制实现访问对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。

线程同步的方式:

  1. 临界区:通过对多线程的串行化来访问公共资源或者一段代码,速度快,适合控制数据访问
  2. 互斥量:采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以可以保证公共资源不会同时被多个线程访问
  3. 信号量:它允许多个线程同一时刻访问同一资源,但是需要限制同一时刻访问此资源的最大线程数目。信号量对象对线程的同步方式与前面几种方法不同,信号允许多个线程同时使用共享资源,这与操作系统中PV操作相似。
  4. 事件(信号):通过通知操作的方式来保持多线程的同步,还可以方便的实现多线程的优先级比较的操作

线程机制的优点:

  多线程运行在同一个进程的相同的地址空间内,和采用多进程相比有以下优点:

  1. 创建和撤销线程的开销较之进程要少。创建线程时只需要建立线程控制表相应的表目,或有关队列,而创建进程时,要创建PCB表和初始化,进入有关进程队列,建立它的地址空间和所需资源等。
  2. CPU在线程之间开关时的开销远比进程要少得多。因开关线程都在同一地址空间内,只需要修改线程控制表或队列,不涉及地址空间和其他工作。
  3. 线程机制也增加了通讯的有效性。进程间的通讯往往要求内核的参与,以提供通讯机制和保护机制,而线程间的通讯是在同一进程的地址空间内,共享主存和文件,无需内核参与。

4 进程 VS. 线程

进程与线程之间的关系

  从一定意义上讲,进程就是一个应用程序在处理机上的一次执行过程,它是一个动态的概念,而线程是进程中的一部分,进程包含多个线程在运行。
  在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位。由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统内多个程序间并发执行的程度。

进程与线程之间的区别

1、调度:
  在传统的操作系统中,CPU调度和分派的基本单位是进程。而在引入线程的操作系统中,则把线程作为CPU调度和分派的基本单位,进程则作为资源拥有的基本单位,从而使传统进程的两个属性分开,线程编程轻装运行,这样可以显著地提高系统的并发性。同一进程中线程的切换不会引起进程切换,从而避免了昂贵的系统调用,但是在由一个进程中的线程切换到另一进程中的线程,依然会引起进程切换。

2、并发性:
  在引入线程的操作系统中,不仅进程之间可以并发执行,而且在一个进程中的多个线程之间也可以并发执行,因而使操作系统具有更好的并发性,从而更有效地提高系统资源和系统的吞吐量。例如,在一个为引入线程的单CPU操作系统中,若仅设置一个文件服务进程,当它由于某种原因被封锁时,便没有其他的文件服务进程来提供服务。在引入线程的操作系统中,可以在一个文件服务进程设置多个服务线程。当第一个线程等待时,文件服务进程中的第二个线程可以继续运行;当第二个线程封锁时,第三个线程可以继续执行,从而显著地提高了文件服务的质量以及系统的吞吐量。

3、拥有资源:
  不论是引入了线程的操作系统,还是传统的操作系统,进程都是拥有系统资源的一个独立单位,他可以拥有自己的资源。一般地说,线程自己不能拥有资源(也有一点必不可少的资源),但它可以访问其隶属进程的资源,亦即一个进程的代码段、数据段以及系统资源(如已打开的文件、I/O设备等),可供同一个进程的其他所有线程共享。

4、独立性:
  在同一进程中的不同线程之间的独立性要比不同进程之间的独立性低得多。这是因为为了防止进程之间彼此干扰和破坏,每个进程都拥有一个独立的地址空间和其它资源,除了共享全局变量外,不允许其它进程的访问。但是同一进程中的不同线程往往是为了提高并发性以及进行相互之间的合作而创建的,它们共享进程的内存地址空间和资源,如每个线程都可以访问它们所属进程地址空间中的所有地址,如一个线程的堆栈可以被其它线程读、写,甚至完全清除。

5、系统开销:
  由于在创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、I/O设备等。因此,操作系统为此所付出的开销将显著地大于在创建或撤消线程时的开销。在进程切换时,涉及到整个当前进程CPU环境的保存环境的设置以及新被调度运行的CPU环境的设置,而线程切换只需保存和设置少量的寄存器的内容,并不涉及存储器管理方面的操作,可见,进程切换的开销也远大于线程切换的开销。此外,由于同一进程中的多个线程具有相同的地址空间,致使他们之间的同步和通信的实现也变得比较容易。在有的系统中,现成的切换、同步、和通信都无需操作系统内核的干预。

6、支持多处理机系统:
  在多处理机系统中,对于传统的进程,即单线程进程,不管有多少处理机,该进程只能运行在一个处理机上。但对于多线程进程,就可以将一个进程中的多个线程分配到多个处理机上,使它们并行执行,这无疑将加速进程的完成。因此,现代处理机OS都无一例外地引入了多线程。

多进程与多线程之间的区别

对比维度 多进程 多线程 总结
数据共享、同步 数据共享复杂,需要用IPC;
数据是分开的,同步简单
因为共享进程数据,数据共享简单,同步复杂 各有优势
内存、CPU 占用内存多,切换复杂,CPU利用率低 占用内存少,切换简单,CPU利用率高 多线程占优
创建销毁、切换 复杂,速度慢 简单,速度快 多线程占优
编程、调试 简单 复杂 多进程占优
可靠性 进程见不会相互影响 一个线程挂掉将导致整个进程挂掉 多进程占优
分布式 适应于多核、多机分布式
如果一台及其不够,扩展到多台机器简单
适应于多核分布式 多进程占优

总结:

  1. 需要频繁创建销毁的优先用线程;
  2. 需要进行大量计算的优先使用线程(最常见的是图像处理、算法处理);
  3. 强相关的处理用线程,弱相关的处理用进程;
  4. 可能要扩展到多机分布的用进程,多核分布的用线程;

5 处理机调度

用户态和核心态

  当程序允许在3级特权级以上时,就可以称之为运行在用户态,因为这是最低特权级,是普通的用户进程运行的特权级,大部分用户直接面对的程序都是运行在用户态;反之当程序运行在特权级上时,就可以称之为运行在内核态。
  用户态切换到内核态的3种方式:系统调用、异常、外围设备的中断。

处理机调度的层次

高级调度(长程调度 / 作业调度)
  调度对象是作业。其主要功能是根据某种算法,决定将外存上处于后备队列中的哪几个作业调入内容,为他们创建进程,分配必要的资源,并将他们放入就绪队列。高级调度主要用于多道批处理系统,而在分时和实时系统中不设置高级调度。
低级调度(短程调度 / 进程调度)
  调度对象是进程(或内核级线程)。其主要功能是根据某种算法,决定就绪队列中的哪个进程应获得处理机,并由分派程序将处理机分配给被选中的进程。进程调度是最基础的一种调度,在多道批处理、分时和实时三种类型的OS中,都必须配置这级调度。
中级调度(内存调度)
  引入中级调度的目的是,提高内存利用率和系统吞吐量。把那些暂时不能运行的进程,调至外存等待,此时进程的状态称为就绪驻外存状态(或挂起状态)。当它们已经具备运行条件且内存又稍有空闲时,由中级调度决定,把外存上的那些已经具备运行条件的就绪进程重新调入内存,并修改状态为就绪状态,挂在就绪队列上等待。中级调度实际上就是存储器管理中的对换功能(交换调度)

操作系统的常见进程调度算法

参考:操作系统的常见进程调度算法

  1. 先来先服务FCFS,First Come First Served)
      先到先执行,简单直观,只需要一个队列(FIFO)就可以实现,相对公平。
      比较有利于长进程,不利于短进程。
  2. 最短作业优先SJF,Shortest Job First)
      对预计执行时间短的进程优先分派处理机。优点是可以减少平均周转时间,缩短进程的等待时间。缺点是不利于长进程,没有依据进程的紧急程度来划分优先级,不能准确估计进程的执行时间,从而影响调度性能。
  3. 最高响应比优先法HRRN,Hightst Response Ratio Next)
      是对FCFS方式和SJF方式的一种综合平衡。
      响应比R=(W+T)/T=1+W/TR = (W+T)/T = 1+W/T,其中T为该作业估计需要的执行时间,W为作业在后备状态队列中的等待时间。RR大的作业优先执行。
    但由于每次调度前要计算响应比,系统开销也要相应增加。
  4. 时间片轮转算法RR,Round-Robin)
      让就绪进程以FCFS 的方式按时间片轮流使用CPU 的调度方式,即将系统中所有的就绪进程按照FCFS 原则,排成一个队列,每次调度时将CPU 分派给队首进程,让其执行一个时间片,时间片的长度从几个ms 到几百ms。在一个时间片结束时,发生时钟中断,调度程序据此暂停当前进程的执行,将其送到就绪队列的末尾,并通过上下文切换执行当前的队首进程,进程可以未使用完一个时间片,就出让CPU(如阻塞)。
      时间片轮转法不利于处理紧急作业。
  5. 多级反馈队列MFQ,Multilevel Feedback Queue)
    目前公认较好的调度算法。
    算法描述:
    • 设置多个就绪队列并为每个队列设置不同的优先级,第一个队列优先级最高,其余依次递减。优先级越高的队列分配的时间片越短;
    • 进程在进入带调度的队列等待时,首先进入优先级最高的队列等待;
    • 首先调度优先级高的队列中的进程。若高优先级中队列中已没有调度的进程,则调度次优先级队列中的进程;
    • 对于同一个队列中的各个进程,按照时间片轮转法调度;比如Q1队列的时间片为N,那么Q1中的作业在经历了N个时间片后若还没有完成,则进入Q2队列等待,若Q2的时间片用完后作业还不能完成,一直进入下一级队列,直至完成。
    • 在低优先级的队列中的进程在运行时,又有新到达的作业,那么在运行完这个时间片后,CPU马上分配给新到达的作业。

6 存储器管理

参考:计算机操作系统(第四版)之存储器管理要点梳理

7 虚拟存储器

  如果存在一个程序,所需内存空间超过了计算机可以提供的实际内存,那么由于该程序无法装入内存也就无法运行,单纯的增加物理内存只能解决一部分问题,但是仍然会出现无法装入单个或者无法同时装入多个程序的问题。但是可以从逻辑的角度扩充内存容量。

定义

  虚拟内存是指具有请求调入功能和置换功能,能从逻辑上对内存容量加以扩充的一种存储器系统。其逻辑容量由内存容量和外村容量之和所决定,其运行速度接近于内存速度,而每位的成本却接近于外存。

特征

  • 多次性
      指一个作业中的程序和数据无需在作业时一次性地全部装入内存,而是允许被分成多次调入内存运行,即指需将当前要运行的那部分程序和数据装入内存即可开始运行;
  • 对换性
      指一个作业中的程序和数据,无需再运行时一致常驻内存,而是允许再作业地运行过程中进行换进、换出;
  • 虚拟性
      指能够从逻辑上扩充内存容量,使用户所看到的内存容量远大于实际内存容量。就可以在小的内存中运行大的作业,或者能提高多道程序度(多道程序度就是多道程序的个数)。

  虚拟性是以多次性和对换性为基础的,
  而多次性和对换性是必须建立在离散分配的基础上。

实现方法

分页请求系统、分段请求系统、段页式虚拟存储器系统

页面置换算法(服务于分页请求系统)

  • 最佳(Optimal)置换算法:只具有理论意义的算法,用来评价其他页面置换算法。置换策略是将当前页面中在未来最长时间内不会被访问的页置换出去。
  • 先进先出(FIFO)置换算法:简单粗暴的一种置换算法,没有考虑页面访问频率信息。每次淘汰最早调入的页面。
  • 最近最久未使用LRU(Least Recently Used)置换算法:算法赋予每个页面一个访问字段,用来记录上次页面被访问到现在所经历的时间t,每次置换的时候把t值最大的页面置换出去(实现方面可以采用寄存器或者栈的方式实现)。
  • 最少使用LFU(Least Frequently Used)置换算法:设置寄存器记录页面被访问次数,每次置换的时候置换当前访问次数最少的。
  • 改进型Clock算法:在Clock算法的基础上添加一个修改位,替换时根究访问位和修改位综合判断。优先替换访问位和修改位都是0的页面,其次是访问位为0修改位为1的页面。
  • 页面缓冲算法(Page Buffering Algorithm,PBA)

常见面试题

  1. 多线程中栈与堆是公有的还是私有的?
    在多线程环境下,每个线程拥有一个栈和一个程序计数器。栈和程序计数器用来保存线程的执行历史和线程的执行状态,是线程私有的资源。其他的资源(比如堆、地址空间、全局变量)是由同一个进程内的多个线程共享。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!