操作系统面试题
一、 进程和线程的区别?
- 进程是资源管理的基本单位,线程是程序执行的基本单位。
- 线程上下文切换比进程上下文切换要快得多。
- 进程是拥有资源的一个独立单位,线程不拥有系统资源,但是可以访问隶属于进程的资源。
- 创建或撤销进程时,系统要为之分配或回收系统资源,付出的开销大于在创建或撤销线程时的开销。
二、 协程与线程的区别?
- 进程和线程都是同步机制,而协程是异步机制。
- 线程是抢占式的,而协程是非抢占式的。需要用户释放使用权切换到其他协程,因此同一时间其实只有一个协程拥有运行权,相当于单线程的能力。
- 一个线程可以有多个协程,一个进程也可以有多个协程。
- 协程不被操作系统内核管理,而完全是由程序控制。线程是被分割的CPU资源,协程是组织好的代码流程,线程是协程的资源。但协程不会直接使用线程,协程直接利用的是执行器关联任意线程或线程池。
- 协程能保留上一次调用时的状态。
三、 进程间通信方式有哪些?
1. 管道
管道通信方式有两种限制,一是半双工的通信,数据只能单向流动,二是只能在具有亲缘关系的进程间使用,即父子进程。
- 匿名管道PIPE:匿名管道是单向的,只能在有亲缘关系的进程间通信。
- 命名管道FIFO:命名管道以磁盘文件的方式存在,可以实现本机任意两个进程通信。
2. 信号
信号是一种比较复杂的通信方式,信号可以在任何时候发给某一进程,而无需知道该进程的状态。
3. 信号量
信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源,因此主要作为进程间以及同一进程内不同线程之间的同步手段。
4. 消息队列
消息队列是消息的链接表,有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
5. 共享内存
共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式,它针对其他进程间通信方式运行效率低而专门设计的,往往与其他通信机制,如信号量配合使用实现进程间的同步和通信。
6. Socket
与其他通信机制不同的是,它可用于不同机器间的进程通信。
四、 进程间同步的方式有哪些?
1. 临界区
通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。只能同步本进程内的线程,而不可用来同步多个进程中的线程。
2. 互斥量
为协调共同对一个共享资源的单独访问而设计的,只有拥有互斥对象的线程才具有访问资源的权限。
3. 信号量
为控制一个具有有限数量用户资源而设计。它允许多个线程在同一时刻访问同一资源,但需要限制在同一时刻访问此资源的最大线程数目。
4. 事件
用来通知线程有些事件已发生,从而启动后继任务的开始。
五、 孤儿进程和僵尸进程
1. 孤儿进程
父进程退出,子进程还在运行的这些进程都是孤儿进程,孤儿进程将被init进程所收养,并由init进程对它们完成状态收集工作。
2. 僵尸进程
进程使用fork创建子进程,如果子进程退出,而父进程没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保留在系统中的这些进程就是僵尸进程。
六、 fork函数
使用fork()创建一个新的进程,新创建的子进程几乎但不完全与父进程相同。在子进程中,成功的fork调用会返回0,在父进程中fork返回子进程的pid(进程识别号)。如果出现错误,fork返回一个负值。
七、 进程调度策略
1. 先来先服务
按照请求的顺序进行调度。有利于长作业,但不利于短作业。
2. 短作业优先
按估计运行时间最短的顺序进行调度。长作业可能会一直处于等待短作业执行完毕的状态。
3. 最短剩余时间优先
最短作业优先的抢占式版本,按剩余运行时间的顺序进行调度。当一个新的作业到达时,其整个运行时间与当前进程的剩余时间作比较,如果新进程需要的时间更少,则挂起当前进程,运行新的进程,否则新的进程等待。
4. 时间片轮转
每个时间片依次执行一个任务,时间片结束后将该任务放回任务队列。
5. 优先级调度
为每个进程分配一个优先级,按优先级进行调度。为防止低优先级的进程永远等不到调度,可以随着时间的推移增加等待进程的优先级。
八、 线程产生的原因
进程可以使多个线程并发执行,提高资源利用率和系统吞吐量,但是进程具有一些缺点:
- 进程在同一时刻只能做一个任务,很多时候不能充分利用CPU资源。
- 进程在执行过程中如果发生阻塞,整个进程就会被挂起,即使进程中其它任务不依赖于等待的资源,进程仍会被阻塞。
线程的优点:
- 从资源上讲,开辟一个线程所需的资源远小于一个进程。
- 从切换效率上讲,运行一个进程中的多个线程,它们之间使用相同的地址空间,而且线程间彼此切换所需的时间也远远小于进程间切换所需的时间。
- 从通信机制上讲,对不同的进程,它们具有独立的地址空间,要进行数据的传递只能通过进程间通信方式进行,而属于同一个进程的不同线程之间共享同一地址空间,所以一个线程的数据可以被其他线程感知,线程间可直接读写进程数据段来进行通信。
九、 线程同步方式
1. 临界区
当多个线程访问一个独占性共享资源时,可以使用临界区对象。拥有临界区的线程可以访问被保护起来的资源或代码段,其他线程若想访问,则被挂起,直到拥有临界区的线程放弃临界区为止,以此达到用原子方式操作共享资源的目的。
2. 事件
事件机制,允许一个线程在处理完一个任务后,主动唤醒另外一个线程执行任务。
3. 互斥量
互斥对象和临界区对象非常相似,只是互斥对象运行在进程间使用,而临界区只限制与同一进程的各个线程之间使用。
4. 信号量
当需要一个计数器来限制可以使用某共享资源的线程数目时,可以使用“信号量”对象。
十、 什么是死锁?死锁产生的条件
1. 死锁
死锁是指两个或多个进程在执行过程中,因争夺资源而造成相互等待的现象。
2. 死锁产生的四个必要条件(必须同时满足)
- 互斥条件:一个资源一次只能被一个进程使用。
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程获得的资源,在未完全使用之前,不能强行剥夺,只能在使用后自己释放。
- 循环等待条件:若干进程之间形成一种头尾相接的环形等待资源关系。
十一、 如何解决死锁问题?
解决死锁问题的方法即破坏产生死锁的四个必要条件之一。
- 资源一次性分配,这样就不会再有请求了。(破坏请求条件)
- 只要有一个资源得不到分配,也不给这个进程分配其他的资源。(破坏请求与保持条件)
- 当进程新的资源未得到满足时,释放已占有的资源。(破坏不剥夺条件)
- 资源有序分配法:系统给每类资源赋予一个序号,每个进程按编号递增的请求资源,释放则相反。(破坏循环等待条件)
十二、 什么是虚拟内存?
虚拟内存是让物理内存扩充成更大的逻辑内存,从而让程序获得更多的可用内存。虚拟内存使用部分加载的技术,让一个进程或资源的某些页面加载进内存,从而加载更多的进程,这样看起来好像内存变大了,这部分内存其实包含了磁盘或者硬盘。
十三、 为什么要引入虚拟内存?
- 虚拟内存作为缓存工具,从逻辑上对内存空间进行扩充,扩大程序的地址空间。
- 虚拟内存为每个进程提供一个一致的、私有的地址空间,多个进程之间互不干扰,也不会访问操作系统所占用的空间。
- 为用户提供方便,逻辑地址和物理地址分开,用户只在各自的逻辑地址空间写程序,不必关心物理地址的细节。
十四、 虚拟内存的实现方式
虚拟内存中,允许将一个作业分多次调入内存,采用连续分配方式,会使相当一部分内存空间都处于暂时或永久空闲状态,造成内存资源的严重浪费,而且无法从逻辑上扩大内存容量。因此,虚拟内存需要建立在离散分配的内存管理方式的基础上。虚拟内存的实现有以下三种方式:
- 请求分页存储管理
- 情求分段存储管理
- 请求段页式存储管理
十五、 什么是分页?什么是分段?两者的区别
1. 分页
分页是为了提高内存利用率,把内存空间划分为大小相等且固定的块,作为主存的基本单位。因为程序数据存储在不同的页面中,而页面又离散地分布在内存中,因此需要一个页表来记录映射关系,以实现从页号到物理块号的映射。
2. 分段
分段是为了满足程序员在编写代码的时候的一些逻辑需求,如数据共享,数据保护等。由于分段管理中,每个段内部是连续内存分配,但是段和段之间是离散分配的,因此需要段表机制实现从逻辑地址到物理地址的映射。
3. 分页和分段的区别
- 分页对程序员是透明的,但是分段需要程序员显示划分每个段。
- 分页的地址空间是一维地址空间。分段是二维的。
- 页的大小不可变,段的大小可以动态改变。
- 分页主要用于实现虚拟内存,从而获得更大的地址空间;分段主要是为了使程序和数据可以被划分为逻辑上独立的地址空间并且有助于共享和保护。
十六、 select、poll和epoll之间的区别
I/O多路复用是通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。
1. select
select仅仅知道有I/O事件发生,但并不知道是哪几个流,所以只能无差别轮询所有流,找出能读出数据或者写入数据的流。
2. poll
poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,但是它没有最大连接数的限制,原因是它是基于链表来存储的。
3. epoll
epoll不同于忙轮询和无差别轮询,epoll会把哪个流发生了怎样的I/O事件通知我们,所以epoll实际上是事件驱动。