操作系统面试题


1~10

1. 什么是用户态和内核态

用户态和内核态是操作系统的两种运行状态。

  • 内核态:可以访问任意的数据,包括外围设备,比如网卡、硬盘等,处于内核态的 CPU 可以从一个程序切换到另外一个程序,并且占用 CPU 不会发生抢占情况,一般处于特权级 0 的状态我们称之为内核态。

  • 用户态:用户态运行的进程可以直接读取用户程序的数据。

2. 如何从用户态切换到内核态呢

  • 系统调用

    这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作,比如 read 操作,比如前例中fork()实际上就是执行了一个创建新进程的系统调用。而系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现,例如Linux的int 80h中断。

  • 异常

    当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。

  • 外围设备的中断

    当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。

3. 并行与并发

  • 并发:在操作系统中,某一时间段,几个程序在同一个CPU上运行,但在任意一个时间点上,只有一个程序在CPU上运行。(一起出发)
  • 并行:两个程序在某一时刻同时运行,强调同时。(一起执行)

4. 同步与异步

  • 同步:指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,知道收到返回信息才继续执行下去;
  • 异步:进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回式系统会通知进程进行处理,这样可以提高执行的效率

5. 线程、进程、协程的区别

  • 进程是资源分配的基本单位,运行一个程序会创建一个或多个进程,进程就是运行起来的可执行程序。

  • 线程是独立调度的基本单位,是轻量级的进程,每个进程里都有一个主线程,且只能有一个,和进程是相互依存的关系,生命周期和进程一样。

  • 协程是用户态的轻量级线程,是线程内部的基本单位。无需线程上下文切换的开销、无需原子操作锁定及同步的开销、方便切换控制流,简化编程模型。

6. 进程和线程的区别

  • 首先从资源来说,进程是资源分配的基本单位,但是线程不拥有资源,线程可以访问隶属进程的资源。

  • 然后从调度来说,线程是独立调度的基本单位,在同一进程中线程切换的话不会引起进程的切换,从一个进程中的线程切换到另一个进程中的线程时,会引起进程的切换。

  • 从系统开销来讲,由于创建或撤销进程,系统都要分配回收资源,所付出的开销远大于创建或撤销线程时的开销。类似的,在进行进程切换的时候,涉及当前执行进程 CPU 环境的保存及新调度进程 CPU 环境设置,而线程切换只需保存和设置少量寄存器的内容,开销很小。

  • 通信方面来说,线程间可以通过直接读写同一进程的数据进行通信,但是进程通信需要借助一些复杂的方法。

7. PCB(Process Control Block)是什么

PCB主要包含下面几部分的内容:

  • 进程的描述信息,比如进程的名称,标识符,
  • 处理机的状态信息,当程序中断是保留此时的信息,以便 CPU 返回时能从断点执行
  • 进程调度信息,比如阻塞原因,状态,优先级等等
  • 进程控制和资源占用,同步通信机制,链接指针(指向队列中下一个进程的 PCB 地址)

PCB 的作用

  • PCB是进程实体的一部分,是操作系统中最重要的数据结构
  • 由于它的存在,使得多道程序环境下,不能独立运行的程序成为一个能独立运行的基本单位,使得程序可以并发执行
  • 系统通过 PCB 来感知进程的存在。(换句话说,PCB 是进程存在的唯一标识)
  • PCB 是进程唯一标识符。

8. 进程的五种状态

有创建状态、就绪状态、运行状态、阻塞状态、结束状态

  • 其中只有就绪状态和运行状态能互相转化,当进程为就绪态时,等待 CPU 分配时间片,得到时间片后就进入运行状态

  • 运行状态在使用完 CPU 时间片后,又重回就绪态。

  • 阻塞状态是进程在运行状态时,需要等待某个资源比如打印机资源,而进入一个挂起的状态,等资源拿到后会回到就绪状态,等待 CPU 时间片。

进程的五种状态及转换

9. 进程调度算法(面试高频考点)

这个看cyc大佬总结的,按批处理系统和交互式系统去记忆比较容易记住。点这里:cycBook

10. 进程同步的方式

  1. 临界区
    首先对临界资源的访问那段代码被称为临界区,为了互斥的访问临界区,每个进程在进入临界区时,都需要先进行检查,也就是查看锁。

  2. 同步与互斥

    为协调共同对一个共享资源的单独访问而设计的

    同步:多个进程因为合作产生的直接制约关系,使得进程有一定的先后顺序。
    互斥:多个进程在同一时刻只有一个进程能进入临界区。

  3. 信号量
    信号量是一个整型变量,可以对其执行 P 和 V 操作。
    P:如果信号量大于零,就对其进行减 1 操作;如果信号量等于 0,进程进入 waiting 状态,等待信号量大于零。
    V:对信号量执行加 1 操作,并唤醒正在 waiting 的进程
    如果信号量只能取 0 或者 1,那么就变成了互斥量,其实也可以理解成加锁解锁操作,0 表示已经加锁,1 表示解锁。

  4. 事件

    用来通知线程有一些事件已发生,从而启动后继任务的开始。

    优点:事件对象通过通知操作的方式来保持线程的同步,并且可以实现不同进程中的线程同步操作。

11. 进程间通信的方式

进程通信和进程同步很容易混淆,其实可以把进程通信当成一种手段,进程同步是一种目的,为了实现进程同步,可传输一些进程同步所需要的信息。

  • 管道
    • 匿名管道:举个例子:linux 里的竖线,就是管道的意思,比如 ps -aux|grep mysql 这句话的意思是把前一个进程查询的结果作为grep mysql的输入,如果两个进程要进行通信的话,就可以用这种管道来进行通信。
      这种通信的方式是半双工通信的,只能单向交替传输
      并且只能在具有亲属关系的进程之间通信使用。
      可以看成是一种特殊的文件,但是这种文件只能存在于内存之中。
    • 命名管道:可以用 mkfifo 命令创建一个命名管道,可以用一个进程向管道里写数据,然后可以让另一个进程把里面的数据读出来。命名管道的优点是去除了只能在父子进程中使用的限制,并且命名管道有路径名和它相关联,是以一种特殊设备文件形式存在于文件系统中的。
  • 消息队列
    • 消息队列的通信模式是这样的:a 进程要给 b 进程发消息,只需要把消息挂在消息队列(可以是中介邮局,也可以是进程自己的信箱)里就行了,b 进程需要的时候再去取消息队列里的消息。
    • 消息队列可以独立于读写进程存在,就算进程终止时,消息队列的内容也不会被删除。
    • 读进程可以根据消息类型有选择的接收消息,而不像 FIFO 那样只能默认接收。
  • 共享内存
    • 共享内存的方式就可以解决拷贝耗时很长的问题了。
    • 共享内存是最快的一种进程通信的方式,因为进程是直接对内存进行存取的。因为可以多个进程对共享内存同时操作,所以对共享空间的访问必须要求进程对共享内存的访问是互斥的。所以我们经常把信号量和共享内存一起使用来实现进程通信。
    • (这里补个知识!!!系统加载一个进程的时候,分配给进程的内存并不是实际的物理内存,而是虚拟内存空间。那么我们可以让两个进程各自拿出一块儿虚拟地址空间来,映射到同一个物理内存中。这样两个进程虽然有独立的虚拟内存空间,但有一部分是映射到相同的物理内存,这样就完成共享机制了。)
  • 信号量
    • 共享内存最大的问题就是多进程竞争内存的问题,就像平时所说的线程安全的问题,那么就需要靠信号量来保证进程间的操作的同步与互斥。
    • 信号量其实就是个计数器,例如信号量的初始值是 1,然后 a 进程访问临界资源的时候,把信号量设置为 0,然后进程 b 也要访问临界资源的时候,发现信号量是 0,就知道已有进程在访问临界资源了,这时进程 b 就访问不了了,所以说信号量也是进程间的一种通信方式。

12. 什么是僵尸进程

僵尸进程是已完成且处于终止状态,但在进程表中却仍然存在的进程。僵尸进程通常发生在父子关系的进程中,由于父进程仍需要读取其子进程的退出状态所造成的。

13. 死锁产生的原因

死锁产生的原因大致有两个:资源竞争和程序执行顺序不当

14. 死锁产生的必要条件

  • 互斥条件:每个资源都被分配给了一个进程或者资源是可用的
  • 保持和等待条件:已经获取资源的进程被认为能够获取新的资源
  • 不可抢占条件:分配给一个进程的资源不能强制的从其他进程抢占资源,它只能由占有它的进程显示释放
  • 循环等待:死锁发生时,系统中一定有两个或者两个以上的进程组成一个循环,循环中的每个进程都在等待下一个进程释放的资源。

15. 死锁的恢复方式

通过抢占进行恢复

在某些情况下,可能会临时将某个资源从它的持有者转移到另一个进程。比如在不通知原进程的情况下,将某个资源从进程中强制取走给其他进程使用,使用完后又送回。这种恢复方式一般比较困难而且有些简单粗暴,并不可取。

通过回滚进行恢复

如果系统设计者和机器操作员知道有可能发生死锁,那么就可以定期检查流程。进程的检测点意味着进程的状态可以被写入到文件以便后面进行恢复。检测点不仅包含存储映像(memory image),还包含资源状态(resource state)。一种更有效的解决方式是不要覆盖原有的检测点,而是每出现一个检测点都要把它写入到文件中,这样当进程执行时,就会有一系列的检查点文件被累积起来。

为了进行恢复,要从上一个较早的检查点上开始,这样所需要资源的进程会回滚到上一个时间点,在这个时间点上,死锁进程还没有获取所需要的资源,可以在此时对其进行资源分配。

杀死进程恢复

最简单有效的解决方案是直接杀死一个死锁进程。但是杀死一个进程可能照样行不通,这时候就需要杀死别的资源进行恢复。

另外一种方式是选择一个环外的进程作为牺牲品来释放进程资源。

16. 如何破坏死锁

和死锁产生的必要条件一样,如果要破坏死锁,也是从下面四种方式进行破坏。

破坏互斥条件

如果资源不被一个进程独占,那么死锁肯定不会产生。如果两个打印机同时使用一个资源会造成混乱,打印机的解决方式是使用 假脱机打印机(spooling printer) ,这项技术可以允许多个进程同时产生输出,在这种模型中,实际请求打印机的唯一进程是打印机守护进程,也称为后台进程。后台进程不会请求其他资源。我们可以消除打印机的死锁。

后台进程通常被编写为能够输出完整的文件后才能打印,假如两个进程都占用了假脱机空间的一半,而这两个进程都没有完成全部的输出,就会导致死锁。

因此,尽量做到尽可能少的进程可以请求资源。

破坏保持等待的条件

第二种方式是如果我们能阻止持有资源的进程请求其他资源,我们就能够消除死锁。一种实现方式是让所有的进程开始执行前请求全部的资源。如果所需的资源可用,进程会完成资源的分配并运行到结束。如果有任何一个资源处于频繁分配的情况,那么没有分配到资源的进程就会等待。

很多进程无法在执行完成前就知道到底需要多少资源,如果知道的话,就可以使用银行家算法;还有一个问题是这样无法合理有效利用资源

还有一种方式是进程在请求其他资源时,先释放所占用的资源,然后再尝试一次获取全部的资源。

破坏不可抢占条件

破坏不可抢占条件也是可以的。可以通过虚拟化的方式来避免这种情况。

破坏循环等待条件

现在就剩最后一个条件了,循环等待条件可以通过多种方法来破坏。一种方式是制定一个标准,一个进程在任何时候只能使用一种资源。如果需要另外一种资源,必须释放当前资源。


文章作者: Allen Sun
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Allen Sun !
评论
  目录