面试专题——操作系统

网友投稿 567 2022-05-29

文章目录

进程是什么?

并行和并发有什么区别吗?

进程什么时候会被创建,并生成PBC?

进程怎么初始化的?

进程的状态?

五种状态模型

七种状态模型

什么会有挂起状态?

挂起状态有什么?

进程控制块(进程控制结构)

PBC具体包含什么呢?

每个PBC如何组织起来的呢?

就绪队列和阻塞队列的链表的组织形式?

进程如何切换?

进程切换定义?

进程切换步骤?

上下问切换的场景有哪些?

线程

什么是线程?

线程的上下文切换?

进程与线程的区别?

进程如何调度?

什么是进程调度?

什么时候调度进程?

调度算法分类?

以什么原则调度进程?

进程调度的算法有什么?

先来先服服务(非抢占式)

时间片轮转(抢占式)

最短作业优先

最短剩余时间优先

优先级调度

多级反馈队列调度

进程间通信

进程通信之管道

进程通信之消息队列

什么是消息队列?

消息队列保存在哪?

缺点

进程通信之共享内存

进程通信之信号量

进程通信之信号

进程通信之Socket

总结

进程是什么?

1、进程指的是当我们启动一个程序,运行之后就是一个进程,进程也可以抽象为任务,一个进程对应一个任务或者多个任务。

2、进程是系统进行资源分配和调度的基本单位,是操作系统结构的基础。

并行和并发有什么区别吗?

并行指的是多核CPU,同时运行在某一个时间点。

并发指的是单核cpu上切换任务,形成一种并发执行。

进程什么时候会被创建,并生成PBC?

1、系统初始化

2、通过系统api创建

3、批处理作业初始化

4、有现有进程派生子进程(如fork子进程)

进程怎么初始化的?

给新进程分配一个进程ID

分配内存空间

初始化PCB

进入就绪队列

进程的状态?

五种状态模型

粗的:

细的:

解释:

如图,进入就绪队列,其状态就会变为就绪态。各个状态之间的关系描述如下:

就绪 -> 运行

:当操作系统内存在着调度程序,当需要运行一个新进程时,调度程序选择一个就绪态的进程,让其进入运行态。

运行 -> 就绪

:运行态的进程,会占有CPU(参照一开始的饼状图)。每个进程会被分配一定的执行时间,当时间结束后,重新回到就绪态。

运行 -> 阻塞

:进程请求调用系统的某些服务,但是操作系统没法立即给它(比如这种服务可能要耗时初始化,比如I/O资源需要等待),那么它就会进入阻塞态。

阻塞 -> 就绪

:当等待结束了,就由阻塞态进入就绪态。

运行 -> 终止

:当进程表示自己已经完成了,它会被操作系统终止。

七种状态模型

粗:

细:

什么会有挂起状态?

为了解决内存占用问题,可以将一部分内存中的进程交换到磁盘中,这些被交换到磁盘的进程,会进入挂起状态。

挂起状态有什么?

阻塞挂起状态:进程在外存(硬盘)并等待某个事件的出现;

就绪挂起状态:进程在外存(硬盘),但只要进入内存,即刻立刻运行;

进程控制块(进程控制结构)

1、在操作系统中,是用进程控制块(process control block,PCB)数据结构来描述进程的。

2、PCB 是进程存在的唯一标识,

3、意味着一个进程的存在,必然会有一个 PCB,如果进程消失了,那么 PCB 也会随之消失。

PBC具体包含什么呢?

每个PBC如何组织起来的呢?

1、通过链表的方式进行组织,把具有相同状态的进程链在一起,组成各种队列。

将所有处于就绪状态的进程链在一起,称为就绪队列;

把所有因等待某事件而处于等待状态的进程链在一起就组成各种阻塞队列;

另外,对于运行队列在单核 CPU 系统中则只有一个运行指针了,因为单核 CPU 在某个时间,只能运行一个程序。

就绪队列和阻塞队列的链表的组织形式?

除了链接的组织方式,还有索引方式,它的工作原理:将同一状态的进程组织在一个索引表中,索引表项指向相应的 PCB,不同状态对应不同的索引表。

一般会选择链表,因为可能面临进程创建,销毁等调度导致进程状态发生变化,所以链表能够更加灵活的插入和删除。

进程如何切换?

进程切换定义?

当一个正在运行中的进程被中断,操作系统指定另一个就绪态的进程进入运行态,这个过程就是进程切换,也可以叫上下文切换。

进程切换步骤?

保存处理器上下文环境:将CPU程序计数器和寄存器的值保存到当前进程的私有堆栈里

更新当前进程的PCB(包括状态更变)

将当前进程移到就绪队列或者阻塞队列

根据调度算法,选择就绪队列中一个合适的新进程,将其更改为运行态

更新内存管理的数据结构

新进程内对堆栈所保存的上下文信息载入到CPU的寄存器和程序计数器,占有CPU

上下问切换的场景有哪些?

为了保证所有进程可以得到公平调度,CPU 时间被划分为一段段的时间片,这些时间片再被轮流分配给各个进程。这样,当某个进程的时间片耗尽了,就会被系统挂起,切换到其它正在等待 CPU 的进程运行;

进程在系统资源不足(比如内存不足)时,要等到资源满足后才可以运行,这个时候进程也会被挂起,并由系统调度其他进程运行;

当进程通过睡眠函数 sleep 这样的方法将自己主动挂起时,自然也会重新调度;

当有优先级更高的进程运行时,为了保证高优先级进程的运行,当前进程会被挂起,由高优先级进程来运行;

发生硬件中断时,CPU 上的进程会被中断挂起,转而执行内核中的中断服务程序;

线程

什么是线程?

线程是进程当中的⼀条执⾏流程。

同⼀个进程内多个线程之间可以共享代码段、数据段、打开的⽂件等资源,但每个线程各⾃都有⼀套独⽴的寄存器和栈,这样可以确保线程的控制流是相对独⽴的。

3、线程是CPU调度的基本单位。(操作系统底层存在调度程序,调度程序可调度任务,而单线程进程,每个进程可以对应一个任务。现在,对于多线程的进程,每一个线程最终对于调度程序来说,都是一个任务,如下图(Linux系统))

线程的上下文切换?

当两个线程不是属于同一个进程,则切换的过程就跟进程上下文切换一样;

当两个线程是属于同一个进程,因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保持不动,只需要切换线程的私有数据、寄存器等不共享的数据;

总的来说:线程的上下文切换相比进程,开销要小很多。

进程与线程的区别?

线程是调度的基本单位,而进程则是资源拥有的基本单位。

所以,所谓操作系统的任务调度,实际上的调度对象是线程,而进程只是给线程提供了虚拟内存、全局变量等资源。

对于线程和进程,我们可以这么理解:

当进程只有一个线程时,可以认为进程就等于线程;

当进程拥有多个线程时,这些线程会共享相同的虚拟内存和全局变量等资源,这些资源在上下文切换时是不需要修改的;

另外,线程也有自己的私有数据,比如栈和寄存器等,这些在上下文切换时也是需要保存的。

进程如何调度?

什么是进程调度?

上下问切换,不能进程切换状态,抢CPU资源。

什么时候调度进程?

从就绪态 -> 运行态:当进程被创建时,会进入到就绪队列,操作系统会从就绪队列选择一个进程运行;

从运行态 -> 阻塞态:当进程发生 I/O 事件而阻塞时,操作系统必须另外一个进程运行;

从运行态 -> 结束态:当进程退出结束后,操作系统得从就绪队列选择另外一个进程运行;

调度算法分类?

非抢占式调度算法挑选一个进程,然后让该进程运行直到被阻塞,或者直到该进程退出,才会调用另外一个进程,也就是说不会理时钟中断这个事情。

抢占式调度算法挑选一个进程,然后让该进程只运行某段时间,如果在该时段结束时,该进程仍然在运行时,则会把它挂起,接着调度程序从就绪队列挑选另外一个进程。这种抢占式调度处理,需要在时间间隔的末端发生时钟中断,以便把 CPU 控制返回给调度程序进行调度,也就是常说的时间片机制。

以什么原则调度进程?

CPU 利用率:调度程序应确保 CPU 是始终匆忙的状态,这可提高 CPU 的利用率;

系统吞吐量:吞吐量表示的是单位时间内 CPU 完成进程的数量,长作业的进程会占用较长的 CPU 资源,因此会降低吞吐量,相反,短作业的进程会提升系统吞吐量;

周转时间:周转时间是进程运行和阻塞时间总和,一个进程的周转时间越小越好;

等待时间:这个等待时间不是阻塞状态的时间,而是进程处于就绪队列的时间,等待的时间越长,用户越不满意;

响应时间:用户提交请求到系统第一次产生响应所花费的时间,在交互式系统中,响应时间是衡量调度算法好坏的主要标准。

进程调度的算法有什么?

先来先服服务(非抢占式)

先来先服务(First Come First Serverd, FCFS)。先进就绪队列,则先被调度,先来先服务是最简单的调度算法。

时间片轮转(抢占式)

每一个进程会被分配一个时间片,表示允许该进程在这个时间段运行,如果时间结束了,进程还没运行完毕,那么会通过抢占式调度,将CPU分配给其他进程,该进程回到就绪队列。这是一种最简单最公平的调度算法,但是有可能会存在问题。由于进程的切换,需要耗费时间,如果时间片太短,频繁进行切换,会影响效率。如果进程时间片太长,有可能导致排后面的进程等待太长时间。因此时间片的长度,需要有大致合理的数值。(建议时间片长度在20ms~50ms)

最短作业优先

最短作业优先(Shortest Job First, SJF),顾名思义即进程按照作业时间长短排队,作业时间段的排前面先执行,如下图。

缺点:长作业可能一辈子都运行不了,当短作业特别多的时候,周期太长。

最短剩余时间优先

最短剩余时间优先(Shortest Remaining Time Next),从就绪队列中选择剩余时间最短的进程进行调度。该算法可以理解最短作业优先和时间片轮转的结合。如果没有时间片,那么最短剩余时间其实就是最短作业时间,因为每个进程都是从头执行到尾。

优先级调度

就绪队列存在的进程

按照优先级调度,执行顺序为p1->p3->p2。如果多个进程优先级相同,则按照先来先服务的方式依次执行。

优先级调度可以进一步细分为抢占式和非抢占式。

非抢占式:和上面提及的非抢占式类似,一旦该进程占有CPU就将一直执行到结束或者阻塞。

抢占式:进程执行期间,一旦有更高优先级的进程进入就绪队列,那么该进程就会被暂停,重回就绪队列,让更高优先级的进程执行。但是为了防止最高优先级进程一直执行,每个进程依然有自己的时间片,每次时间片结束后,会根据一定规则降低该进程优先级,避免某些最高优先级长作业进程一直占用CPU。

缺点:低优先级的可能永远都不会执行。

多级反馈队列调度

多级反馈队列调度基于时间片轮转和优先级调度,设置多个就绪队列,赋予每个就绪队列优先级,优先级越高的队列进程的时间片越短。如下图,第1级就绪队列优先级最高,进程的时间片长度最短,第2级就绪队列次之,以此类推。

进程间通信?

每个进程的用户地址空间都是独立的,一般而言是不能互相访问的,但内核空间是每个进程都共享的,所以进程之间要通信必须通过内核。

进程通信之管道

1、管道传输数据是单向的

2、管道这种通信方式效率低,不适合进程间频繁地交换数据

3、它的好处,自然就是简单,同时也我们很容易得知管道里的数据已经被另一个进程读取了。

4、对于匿名管道,它的通信范围是存在父子关系的进程。(ps auxf | grep mysql)

5、对于命名管道,它可以在不相关的进程间也能相互通信。(mkfifo)

匿名:

命名:

进程通信之消息队列

什么是消息队列?

A 进程要给 B 进程发送消息,A 进程把数据放在对应的消息队列后就可以正常返回了,B 进程需要的时候再去读取数据就可以了。同理,B 进程要给 A 进程发送消息也是如此。

消息队列保存在哪?

息队列是保存在内核中的消息链表,在发送数据时,会分成一个一个独立的数据单元,也就是消息体(数据块),消息体是用户自定义的数据类型,消息的发送方和接收方要约定好消息体的数据类型,所以每个消息体都是固定大小的存储块,不像管道是无格式的字节流数据。如果进程从消息队列中读取了消息体,内核就会把这个消息体删除。

消息队列生命周期随内核,如果没有释放消息队列或者没有关闭操作系统,消息队列会一直存在,而前面提到的匿名管道的生命周期,是随进程的创建而建立,随进程的结束而销毁。

缺点

消息队列通信过程中,存在用户态与内核态之间的数据拷贝开销,因为进程写入数据到内核中的消息队列时,会发生从用户态拷贝数据到内核态的过程,同理另一进程读取内核中的消息数据时,会发生从内核态拷贝数据到用户态的过程。

进程通信之共享内存

共享内存的机制,就是拿出一块虚拟地址空间来,映射到相同的物理内存中。

优点:不需要拷贝,大大提高了进程间通信的速度

进程通信之信号量

信号量其实是一个整型的计数器,主要用于实现进程间的互斥与同步,而不是用于缓存进程间通信的数据。(阻止ABA问题)

信号量表示资源的数量,控制信号量的方式有两种原子操作:

一个是 P 操作,这个操作会把信号量减去 -1,相减后如果信号量 < 0,则表明资源已被占用,进程需阻塞等待;相减后如果信号量 >= 0,则表明还有资源可使用,进程可正常继续执行。

另一个是 V 操作,这个操作会把信号量加上 1,相加后如果信号量 <= 0,则表明当前有阻塞中的进程,于是会将该进程唤醒运行;相加后如果信号量 > 0,则表明当前没有阻塞中的进程;

P 操作是用在进入共享资源之前,V 操作是用在离开共享资源之后,这两个操作是必须成对出现的。

接下来,举个例子,如果要使得两个进程互斥访问共享内存,我们可以初始化信号量为 1。

具体的过程如下:

面试专题——操作系统

进程 A 在访问共享内存前,先执行了 P 操作,由于信号量的初始值为 1,故在进程 A 执行 P 操作后信号量变为 0,表示共享资源可用,于是进程 A 就可以访问共享内存。

若此时,进程 B 也想访问共享内存,执行了 P 操作,结果信号量变为了 -1,这就意味着临界资源已被占用,因此进程 B 被阻塞。

直到进程 A 访问完共享内存,才会执行 V 操作,使得信号量恢复为 0,接着就会唤醒阻塞中的线程 B,使得进程 B 可以访问共享内存,最后完成共享内存的访问后,执行 V 操作,使信号量恢复到初始值 1。

可以发现,信号初始化为 1,就代表着是互斥信号量,它可以保证共享内存在任何时刻只有一个进程在访问,这就很好的保护了共享内存。

另外,在多进程里,每个进程并不一定是顺序执行的,它们基本是以各自独立的、不可预知的速度向前推进,但有时候我们又希望多个进程能密切合作,以实现一个共同的任务。

例如,进程 A 是负责生产数据,而进程 B 是负责读取数据,这两个进程是相互合作、相互依赖的,进程 A 必须先生产了数据,进程 B 才能读取到数据,所以执行是有前后顺序的。

那么这时候,就可以用信号量来实现多进程同步的方式,我们可以初始化信号量为 0。

具体过程:

如果进程 B 比进程 A 先执行了,那么执行到 P 操作时,由于信号量初始值为 0,故信号量会变为 -1,表示进程 A 还没生产数据,于是进程 B 就阻塞等待;

接着,当进程 A 生产完数据后,执行了 V 操作,就会使得信号量变为 0,于是就会唤醒阻塞在 P 操作的进程 B;

最后,进程 B 被唤醒后,意味着进程 A 已经生产了数据,于是进程 B 就可以正常读取数据了。

可以发现,信号初始化为 0,就代表着是同步信号量,它可以保证进程 A 应在进程 B 之前执行。

进程通信之信号

1、信号是进程间通信机制中唯一的异步通信机制。

**2、**进程需要为信号设置相应的监听处理,当收到特定信号时,执行相应的操作,类似很多编程语言里的通知机制。

3、如kill,Ctrl+C,Ctrl+Z都是信号

进程通信之Socket

1、跨网络与不同主机上的进程之间通信,就需要 Socket 通信了

**2、**Socket 通信不仅可以跨网络与不同主机的进程间通信,还可以在同主机上进程间通信

总结

任务调度 数据结构

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:第三天、计算某日是该年的第几天
下一篇:【精讲】2022年PHP中高级面试题(二)
相关文章