操作系统面经合集

1、并发和并行

并发:当有多个线程在操作时,如果系统只有一个CPU,每一个时间段只有一个线程执行,其他线程挂起

并行:当系统有一个以上CPU时,则线程的操作有可能非并发。每个CPU都可以分配给线程,线程可以同时进行。

并发是多个事件有先后顺序的执行,并行是多个事件同时进行。

2、多线程和多进程

多进程:指计算机同时执行多个进程(多个软件)。进程与资源有关,是系统进行资源分配和调度的独立单元。

进程实体

由程序段、相关数据段和PCB(程序控制块,为了使参与并发执行的程序能够独立运行而专门设置的一个数据结构,他是进程存在的唯一标识)组成。

进程的分类

有系统进程和用户进程,用于完成系统各个功能的进程叫系统进程,而所有由用户启动的都是用户进程。

多线程:多线程是一种执行模型,包括多对一、一对一、多对多模型。

举例

多线程同一时刻执行多个线程。如,用浏览器一边下载,一边听歌,一边看视频,一边看网页

多进程同时执行多个程序。如,同事运行微信,QQ,以及各种浏览器。

优劣 多进程 多线程
优点 编程、调试简单,可靠性较高 创建、销毁、切换速度快,内存、资源占用小
缺点 创建、销毁、切换速度慢,内存、资源占用大 编程、调试复杂,可靠性较差

2.1多线程使用要注意哪些事项

线程之间共用进程所有资源,当多线程操作同一个变量的时候,可能会使得结果不正确。

因此要特别注意线程安全的问题。

通常保证线程安全有很多种方式

  • 使用线程锁

  • 使用串行队列

  • 使用线程安全的类

  • 使用信号量或runloop使异步看起来像同步在执行

  • 注意任务可能本身就是异步的

3、线程与进程的区别

进程是资源分配的最小单位,线程是CPU调度的最小单位

进程是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例。程序运行时系统就会创建一个进程,并为它分配资源,然后把该进程放入进程就绪队列,进程调度器选中它的时候就会为它分配CPU时间,程序开始真正运行。

线程是程序执行时的最小单位,它是进程的一个执行流,是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。线程由CPU独立调度执行。在多CPU环境下就允许多个线程同时运行。同样多线程也可以实现并发操作,每个请求分配一个线程来处理。

进程和线程的区别

  • 进程是资源分配的基本单位,线程是程序执行的最小单位;每个进程可执行多个线程,线程是进程执行运算的最小单位;

  • 线程是轻量级的进程,所消耗的资源和切换代价比较小,但不利于资源的管理和保护;

  • 进程是独立的,而各个线程则不一定,同一个进程中的线程极有可能会相互影响。

  • 进程有自己的地址空间,线程是共享地址空间

  • 属于同一进程的线程,堆是共享的,栈是私有的。

  • 属于同一进程的所有线程都具有相同的地址空间。

一个进程可以创建的线程数由可用虚拟空间和线程的栈的大小共同决定

4、大小端存储

大端模式:是指数据的高字节,保存在内存的低地址中,而数据的低字节保存在内存的高地址;

小端模式:是指数据的高字节,保存在内存的高地址中,而数据的低字节保存在内存的低地址。

优缺点:

大端模式优点:符号位在所表示的数据的内存的第一个字节中,便于快速判断数据的正负和大小(我们平时阅读顺序) 小端模式优点:

  1. 内存的低地址处存放低字节,所以在强制转换数据时不需要调整字节的内容(注解:比如把int的4字节强制转换成short的2字节时,就直接把int数据存储的前两个字节给short就行,因为其前两个字节刚好就是最低的两个字节,符合转换逻辑);

  2. CPU做数值运算时从内存中依顺序依次从低位到高位取数据进行运算,直到最后刷新最高位的符号位,这样的运算方式会更高效

判断:

方法一:通过将多字节数据强制类型转换成单字节数据,再通过判断起始存储位置是数据高字节还是低字节进行检测

方法二:利用联合体union(所有成员共享同一块内存)的存放顺序是所有成员都从低地址开始存放这一特性进行检测——数组从低到高

5、进程间的通信方法?线程间的通信方法?

5.1、进程间

  1. 管道(pipe):速度慢,容量有限,只有父子进程通讯;(通信的方式是匿名的,所以只能用于具有亲缘关系的进程间通信)

    父子进程:在一个进程的基础上创建出另一条完全独立的进程

  2. 命名管道(FIFO):任何进程间都能通讯,但速度慢;(提供一个路径名与之关联)

  3. 消息队列(MessageQueue):容量收到系统限制;

  4. 信号量(Semaphore):不能传递复杂消息,不具有数据交换功能,只能同步,是用来管理临界资源的(计数器、PV操作)

    防止多个程序同时访问一个共享资源而引发一系列问题,在任何时刻只能有一个执行线程访问代码的临界区域

  5. 共享内存(SharedMemory):很容易控制容量,速度快(没有提供相应的互斥机制)但保持同步

  6. 套接字(Socket):一种进程间通信机制,可用于不同及其间的进程通信。

  7. 信号(sinal):信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

5.1.4临界区,临界资源

临界资源:一次只允许一个进程使用的资源。

临界区:访问临界资源的程序代码片段。

5.2、线程间

主要用于线程同步(没有像进程通信中的用于数据交换的通信机制)

  1. 锁机制:包括互斥锁、条件变量、读写锁

    • 互斥锁提供了以排他方式防止数据结构被并发修改的方法。

    • 读写锁允许多个线程同时读共享数据,而对写操作是互斥的。

    • 条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。

  2. 信号量机制:包括无名线程信号量和命名线程信号量

  3. 信号机制:类似进程间的信号处理

5.2.1、线程有几种状态,怎样转换?

New 新建状态:新建一个线程对象;

Runnable 可运行状态: 等待操作系统分配资源(如CPU)、等待IO连接、正在运行状态 ;

Blocked 被阻塞状态:

Waiting 等待状态:

Timed Waiting 计时等待状态:

Terminated 终止:

6、进程的都有哪些状态?怎么转换的?

创建态:进程正在被创建,尚未到就绪状态

就绪态:进程已处于准备运行状态,即进程获得了除了处理器之外的一切所需资源,一旦获得处理器资源即可运行

运行态:进程正在处理器上运行

阻塞态:又称等待状态,进程正在等待某一事件而暂停运行如等待某资源为可用或等待IO操作完成。即使处理器空闲,进程也不能运行

终结态:进程正在从系统中消失,可能是进程正常结束或其他原因中途退出

6.1、调度有哪些

  1. 作业调度--高级调度

    用于决定将外存上处于后备队列中的哪些作业调入内存,处于内存的就绪队列,准备执行。

  2. 进程调度--低级调度

    决定就绪队列中那个进程将获得处理机

  3. 交换调度--中级调度

    目的是提高内存的利用率和系统的吞吐量

6.2、引起进程调度的原因

  1. 正在执行的进程执行完毕

  2. 执行中的进程因提出I/O请求或发生等事件而暂停执行。

  3. 时间片完成

  4. 在进程通信或同步过程中执行了某种原语操作,如P操作(wait操作)阻塞

  5. 高优先者进入

6.3调度的方式

1.非剥夺方式(非抢占方式)—— 先来先服务,短作业

一旦占用CPU,直至完成或阻塞

不利用实时任务,不利用短作业;使用于批处理系统

2.剥夺方式(抢占方式) ——短作业,高相应比优先

在一定情况下,可剥夺一进程占有的处理机

抢占的原则有:短作业(进程)优先原则、时间片原则、优先权原则。

7、进程的状态和装换

7.1、三态模型:

运行(running)态:进程占有处理器正在运行的状态。 进程已获得CPU,其程序正在执行。在单处理机系统中,只有一个进程处于执行状态; 在多处理机系统中,则有多个进程处于执行状态。

就绪(ready)态:进程具备运行条件,等待系统分配处理器以便运行的状态。当进程已分配到除CPU以外的所有必要资源后,只要再获得CPU,便可立即执行,进程这时的状态称为就绪状态。在一个系统中处于就绪状态的进程可能有多个,通常将它们排成一个队列,称为就绪队列。

等待(wait)态:又称阻塞态或睡眠态,指进程不具备运行条件,正在等待某个时间完成的状态。也称为等待或睡眠状态,一个进程正在等待某一事件发生(例如请求I/O而等待I/O完成等)而暂时停止运行,这时即使把处理机分配给进程也无法运行,故称该进程处于阻塞状态。

引起进程状态转换的具体原因如下:
运行态→等待态:等待使用资源;如等待外设传输;等待人工干预。
等待态→就绪态:资源得到满足;如外设传输结束;人工干预完成。
运行态→就绪态:运行时间片到;出现有更高优先权进程。
就绪态—→运行态:CPU 空闲时选择一个就绪进程。

7.2、五态模型

五态模型在三态模型的基础上增加了新建态(new)和终止态(exit)。

新建态:对应于进程被创建时的状态,尚未进入就绪队列。 创建一个进程需要通过两个步骤:1.为新进程分配所需要资源和建立必要的管理信息。2.设置该进程为就绪态,并等待被调度执行。

终止态:指进程完成任务到达正常结束点,或出现无法克服的错误而异常终止,或被操作系统及有终止权的进程所终止时所处的状态。处于终止态的进程不再被调度执行,下一步将被系统撤销,最终从系统中消失。终止一个进程需要两个步骤:1.先等待操作系统或相关的进程进行善后处理(如抽取信息)。2.然后回收占用的资源并被系统删除。

引起进程状态转换的具体原因如下:
NULL→新建态:执行一个程序,创建一个子进程。
新建态→就绪态:当操作系统完成了进程创建的必要操作,并且当前系统的性能和虚拟内存的容量均允许。
运行态→终止态:当一个进程到达了自然结束点,或是出现了无法克服的错误,或是被操作系统所终结,或是被其他有终止权的进程所终结。
运行态→就绪态:运行时间片到;出现有更高优先权进程。
运行态→等待态:等待使用资源;如等待外设传输;等待人工干预。
就绪态→终止态:未在状态转换图中显示,但某些操作系统允许父进程终结子进程。
等待态→终止态:未在状态转换图中显示,但某些操作系统允许父进程终结子进程。
终止态→NULL:完成善后操作。

7.3、七态模型

七态模型在五态模型的基础上增加了挂起就绪态(ready suspend)和挂起等待态(blocked suspend)。

挂起就绪态:进程具备运行条件,但目前在外存中,只有它被对换到内存才能被调度执行。

挂起等待态:表明进程正在等待某一个事件发生且在外存中。

引起进程状态转换的具体原因如下:
等待态→挂起等待态:操作系统根据当前资源状况和性能要求,可以决定把等待态进程对换出去成为挂起等待态。
挂起等待态→挂起就绪态:引起进程等待的事件发生之后,相应的挂起等待态进程将转换为挂起就绪态。
挂起就绪态→就绪态:当内存中没有就绪态进程,或者挂起就绪态进程具有比就绪态进程更高的优先级,系统将把挂起就绪态进程转换成就绪态。
就绪态→挂起就绪态:操作系统根据当前资源状况和性能要求,也可以决定把就绪态进程对换出去成为挂起就绪态。
挂起等待态→等待态:当一个进程等待一个事件时,原则上不需要把它调入内存。但是在下面一种情况下,这一状态变化是可能的。当一个进程退出后,主存已经有了一大块自由空间,而某个挂起等待态进程具有较高的优先级并且操作系统已经得知导致它阻塞的事件即将结束,此时便发生了这一状态变化。
运行态→挂起就绪态:当一个具有较高优先级的挂起等待态进程的等待事件结束后,它需要抢占 CPU,而此时主存空间不够,从而可能导致正在运行的进程转化为挂起就绪态。另外处于运行态的进程也可以自己挂起自己。
新建态→挂起就绪态:考虑到系统当前资源状况和性能要求,可以决定新建的进程将被对换出去成为挂起就绪态。

8、挂起进程的特征

  • 该进程不能立即被执行

  • 挂起进程可能会等待一个事件,但所等待的事件是独立于挂起条件的,事件结束并不能导致进程具备执行条件。 (等待事件结束后进程变为挂起就绪态)

  • 进程进入挂起状态是由于操作系统、父进程或进程本身阻止它的运行。

  • 结束进程挂起状态的命令只能通过操作系统或父进程发出。

8.1、引起进程挂起的原因

  1. 终端用户的请求。当终端用户在自己的程序运行期间发现有可疑问题时,希望暂停使自己的程序静止下来。亦即,使正在执行的进程暂停执行;若此时用户进程正处于就绪状态而未执行,则该进程暂不接受调度,以便用户研究其执行情况或对程序进行修改。我们把这种静止状态成为“挂起状态”。

  2. 父进程的请求。有时父进程希望挂起自己的某个子进程,以便考察和修改子进程,或者协调各子进程间的活动。

  3. 负荷调节的需要。当实时系统中的工作负荷较重,已可能影响到对实时任务的控制时,可由系统把一些不重要的进程挂起,以保证系统能正常运行。

  4. 操作系统的需要。操作系统有时希望挂起某些进程,以便检查运行中的资源使用情况或进行记账。

  5. 对换的需要。为了缓和内存紧张的情况,将内存中处于阻塞状态的进程换至外存上。

9、线程同步的方式

  1. 信号量:允许一时刻多个线程访问同一个资源,但需要控制一时刻访问此资源的最大线程数量;

  2. 互斥量:实际上是信号量的一种特殊情况,允许同一时刻只有一个线程访问同一个资源;

  3. 信号(事件):通过通知操作的方式来保证多线程同步,还可以方方便实现多线程优先级的比较操作。

10、死锁及产生条件

(并发中的死锁)在两个或者多个并发进程中,如果每个进程持有某种资源,又等待其他进程释放它目前持有的资源,在未改变这种状态之前,都不能向前推进。这一情况被称作死锁

死锁产生的四个条件:

  • 互斥条件:一个资源一次只能被一个进程使用

  • 请求与保持条件:一个进程因请求资源而阻塞时,对其自身拥有的资源保持不放

  • 不可剥夺条件:进程获得的资源,在未完全使用完之前,不能强行剥夺

  • 循环等待条件:若干进程之前形成一种头尾相接的环形等待资源关系

10.1、解决死锁的基本方法:

预防死锁,避免死锁,检测死锁,解决死锁

  • 预防死锁:确保死锁发生的四个必要条件中,至少有一个不成立

  • 避免死锁:动态检测资源分配状态,确保循环等待条件不成立,使系统处于安全状态

  • 解决死锁:包括进程终止和资源抢占

    • 选择一个牺牲品

    • 回滚

    • 饥饿(使回滚得越多的,越不可能继续作为牺牲品)

  • 避免死锁:

    • 破坏互斥条件:这个条件没有办法破坏,我们使用锁就是为了让他们互斥临界资源。

    • 破坏请求与保持条件:一次性申请所有资源

    • 破坏不剥夺资源:占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。

    • 破坏循环等待条件:靠按需申请资源来预防。

11、内核态和用户态,特权和非特权

内核态:当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态。

用户态:用户程序运行在用户态,操作系统运行在内核态。

特权指令:只能由操作系统内核部分使用,不允许用户直接使用的指令。如I/O指令、置终端屏蔽指令、清内存、建存储保护、设置时钟指令。

非特权指令:所有程序均可直接使用。

系统态(核心态、特态、管态):执行全部指令。 用户态(常态、目态):执行非特权指令。

11.1 用户态内核态转换

中断实现

进行转换,要执行栈的转换,需要保存用户态的寄存器,在内核态返回用户态的时候会恢复这些寄存器的内容,相对而言这是一个很大的开销且耗时。

a. 系统调用

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

b. 异常

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

c. 外围设备的中断

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

11.2 内核态

(1) I/O指令、置终端屏蔽指令、清内存、建存储保护、设置时钟指令。

(2) 中断、异常、陷入,比如缺页中断等

(3)进程(线程)管理

(4)系统调用,比如调用了设备驱动程序

(5)用户内存地址的转换(逻辑---> 物理映射)

12、什么是操作系统

  • 操作系统(Operating System,简称 OS)是管理计算机硬件与软件资源的程序,是计算机系统的内核与基⽯;

  • 操作系统本质上是运⾏在计算机上的软件程序 ;

  • 操作系统为⽤户提供⼀个与系统交互的操作界⾯ ;

  • 操作系统分内核与外壳(我们可以把外壳理解成围绕着内核的应⽤程序,⽽内核就是能操作硬件的程序)。

13、内存管理方式?

  • 块式:将内存分为几个固定大小的块,每个块只包含一个进程。如果程序需要小部分的空间,而却分出较大的空间,就会导致内存浪费,也就是常说的“碎片”。

  • 页式:把贮存分为大小相等的一页一页形式,页较小,对比于块式的划分力度更大,提高了内存利用率,减少碎片。

  • 段式:页式管理虽然提高了内存利用率,但是页式管理其中的页实际并无任何实际意义。段式管理把主存分为⼀段段的,每⼀段的空间又要比一页的空间小很多。

  • 段页式:段页式管理机制结合了段式管理和页式管理的优点。简单来说段页式管理机制就是把主存先分成若干段,每个段又分成若⼲页,也就是说 段页式管理机制 中段与段之间以及段的内部的都是离散的。

14、孤儿进程和僵尸进程?

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵尸进程。

僵尸进程的解决办法:

  • 通过信号量机制。子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程。

  • fork两次,原理是将子进程成为孤儿进程,从而其的父进程变为init进程,通过init进程可以处理僵尸进程。

僵尸进程危害场景:

  例如有个进程,它定期的产 生一个子进程,这个子进程需要做的事情很少,做完它该做的事情之后就退出了,因此这个子进程的生命周期很短,但是,父进程只管生成新的子进程,至于子进程 退出之后的事情,则一概不闻不问,这样,系统运行上一段时间之后,系统中就会存在很多的僵死进程,倘若用ps命令查看的话,就会看到很多状态为Z的进程。 严格地来说,僵死进程并不是问题的根源,罪魁祸首是产生出大量僵死进程的那个父进程。因此,当我们寻求如何消灭系统中大量的僵死进程时,答案就是把产生大 量僵死进程的那个元凶枪毙掉(也就是通过kill发送SIGTERM或者SIGKILL信号啦)。枪毙了元凶进程之后,它产生的僵死进程就变成了孤儿进 程,这些孤儿进程会被init进程接管,init进程会wait()这些孤儿进程,释放它们占用的系统进程表中的资源,这样,这些已经僵死的孤儿进程 就能瞑目而去了。

15、程序的开始到结束过程

预处理——编译——汇编——链接

  • .c文件经过预处理器,生成中间件.i文件。这个阶段有两个作用,一是把include的头文件内容进行替换,二是处理宏定义。

  • .i 文件经过编译生成汇编.s 文件

  • .s 的汇编文件经过汇编器生成.obj 的目标文件

  • .obj 经过链接器和 lib(静态链接库)、 dll(动态链接库)文件生成 exe 可执行程序。

16、中断和异常的区别

中断是指 CPU 对系统发生某事件时的这样一种响应:CPU 暂停正在执行的程序,在保留现场后自动地转去执行该事件的中断处理程序;执行完后,再返回到原程序的断点处继续执行。还可进一步把中断分为外中断和内中断:

  • 外中断——就是我们指的中断——是指由于外部设备事件所引起的中断, 如通常的磁盘中断、打印机中断等;

  • 内中断——就是异常——是指由于 CPU 内部事件所引起的中断, 如程序出错(非法指令、地址越界)。 内中断(trap)也被译为“捕获”或“陷入”。

==异常==是由于执行了现行指令所引起的。由于系统调用引起的中断属于异常。

==中断==则是由于系统中某事件引起的,该事件与现行指令无关。

相同点:都是CPU对系统发生的某个事情做出的一种反应。 区别:中断由外因引起,异常由CPU本身原因引起。

17、扇区、块、页、簇的概念

操作系统与磁盘之间交流的最小单位就是磁盘块 。

(1) 什么是簇?和块什么区别?

    在Windows下如NTFS等文件系统中叫做簇;在Linux下如Ext4等文件系统中叫做块。每个簇或者块可以包括2的n次方个扇区。 

(2) 为什么存在磁盘块?

读取方便:由于扇区的数量比较小,数目众多在寻址时比较困难,所以操作系统就将相邻的扇区组合在一起,形成一个块,再对块进行整体的操作。

  分离对底层的依赖:操作系统忽略对底层物理存储结构的设计。通过虚拟出来磁盘块的概念,在系统中认为块是最小的单位。

(3) 块与页的关系

操作系统经常与内存和硬盘这两种存储设备进行通信,类似于“块”的概念,都需要一种虚拟的基本单位。所以,与内存操作,是虚拟一个页的概念来作为最小单位。与硬盘打交道,就是以块为最小单位。

猜你喜欢

转载自blog.csdn.net/slave_of_life/article/details/130490849#comments_26326493