专题:操作系统常见问题及面试问题汇总

一、进程、线程

1、进程优先级反转?

定义:高优先级进程因为某种原因等待低优先级进程

解决办法:

优先级继承法:优先级较低的任务继承任何与它共享同一资源的优先级较高任务的优先级。资源释放时,继承结束。

优先级置顶法:设定资源优先级为最高优先级用户,调度器动态分配资源优先级到访问该资源的任务。

2、进程与线程,定义,联系,区别?

进程定义:正在执行的程序实例。由程序、数据、栈、进程控制块组成。拥有资源所有权。拥有的资源包括虚拟地址空间、内存、io通道、io设备、文件

进程的内存表示如下:

|进程标识符|处理器状态信息|进程控制信息|用户栈|用户地址空间(程序、数据)|内核栈|共享地址空间

|            进程控制块                                       |

 

线程:是一个可被调度和分派的实体,具有一个执行状态和优先级。是调度的基本单位。

线程优点:   创建时间比进程短。快10倍左右。

终止一个线程比终止一个进程时间要短。

同一进程间线程切换比进程切换开销少。

提高了通信效率。(原因:线程之间共享了内存和文件)

3、用户级线程与内核级线程,定义,优缺点?

用户级线程:线程管理的操作由应用程序完成。(线程调度发生在用户程序中)

优点:   线程都在一个进程的用户地址空间,线程切换不需要内核态特权,节省了开销

调度可以是应用程序相关的。

用户级线程可以在任何系统中运行,无需修改底层。

缺点: 用户级线程执行系统调用时会阻塞,从而阻塞进程,进而阻塞进程的所有线程

纯粹的用户级线程,一个多线程应用程序不能利用多处理技术。因为内核一次只能给一个进程分配处理器,一个进程中只有一个线程可以执行)

内核级线程:纯粹的内核线程,有关线程管理的工作全部由内核完成。

优点:   一个进程中的多个线程可以调度到多个处理器中。

如果一个线程被阻塞可以调度同一个进程中的另一个线程

内核例程本身可以使用多线程

缺点: 线程切换时需要内核的状态切换,开销较大。

4、进程切换的详细过程?

何时切换:

时钟中断、IO中断、内存失效

如何切换:

模式切换:

a             将程序计数器置成中断处理程序开始抵制

b             从用户态切换到内核态,使得中断处理可以包含特权指令

进程状态切换:

a             保存上下文环境

b             更新进程控制块(状态等其他信息)

c             将进程的进程控制块移动到相关队列(就绪,在事件i阻塞,挂起)

d             选择另一个进程执行

e             更新所选择进程的进程控制块

f             更新内存管理相关数据结构

h             恢复当前进程的上下文环境

5、线程安全函数定义?

定义:一个函数被称为线程安全的,当且仅当被多个并发线程反复调用时,它会一直产生正确的结果。

确保线程安全:主要需要考虑的是线程之间的共享变量,必须通过加锁的方式。

不安全后果:共享变量的值由于不同线程的访问,可能发生不可预料的变化,进而导致程序的错误,甚至崩溃。

6、可重入函数定义?

定义:“A computerprogram or routine is described as reentrant if it can be safely executedconcurrently;that is, the routine can be re-entered while it is alreadyrunning.”

程序执行到某个函数foo()时,收到信号,于是暂停目前正在执行的函数,转到信号处理 函数,而这个信号处理函数的执行过程中,又恰恰也会进入到刚刚执行的函数foo(),这样便发生了所谓的重入。此时如果foo()能够正确的运行,而且处理完成后,之前暂停的foo()也能够正确运行,则说明它是可重入的。

如何确保函数可重入:

1、不在函数内部使用静态或全局数据

2、不返回静态或全局数据,所有数据都由函数的调用者提供。

3、使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据。

4、不调用不可重入函数

不可重入后果:主要体现在象信号处理函数这样需要重入的情况中,可能导致程序的错误甚至崩溃。

7、可重入与线程安全的区别?

可重入与线程安全并不等同。一般说来,可重入的函数一定是线程安全的,但反过来不一定成立。

如果一个函数中用到了全局或静态变量,那么它不是线程安全的,也不是可重入的; 如果我们对它加以改进,在访问全局或静态变量时使用互斥量或信号量等方式加锁,则可以使它变成线程安全的,

但此时它仍然是不可重入的,因为通常加锁方式是针对不同线程的访问,而对同一线程可能出现问题。

二、调度

1、操作系统常见任务调度算法,linux呢,liteos呢?

常见任务调度算法:

FCFS 先来先服务:优点,执行长进程比执行短进程好。

RR 轮转法:主要设计问题:时间片的长度。时间片最好略大于一次典型交互所需要的时间。

SPN        最短进程优先:选择预计处理时间最短的进程。

SRT 最短剩余时间:选择预期剩余时间最短的进程。

HRRN 最高响应比优先:选择比值最大的就绪进程。(周转时间和实际服务时间比值)

周转时间=实际服务时间+等待时间)

反馈:调度基于抢占原则并且使用动态优先级机制。每个队列使用先来先服务算法

 

linux调度算法:

inux调度的本质问题:分配绝对的时间片引发的固定的切换频率,给公平性造成了很大变数。

CFS 完全公平调度器:完全摒弃时间片而是分配给进程一个处理器使用比重。确保进程调度恒定的公平性,而将切换频率置于不断变动中。任何进程所获得的处理器时间是由它自己和和其它所有可运行的进程nice值的相对差值决定。nice值对应的绝对时间不再是一个绝对值,而是处理器使用比。

实时调度器:

 

SCHED_FIFO调度算法:

简单的先入先出算法。                                                                                                  高优先级SCHED_FIFOSCHED_RR任务可抢占低优先级SCHED_FIFO任务。                                                                                                      同优先级只有当当前SCHED_FIFO愿意让出处理器,另一个才能调度执行。                                                                                                      低优先级只能等待当前SCHED_FIFO变为不可运行态

SCHED_RR调度算法: 只用来调度同一优先级的进程。

liteos调度算法:

                  liteOS是基于优先级的抢占式,同等优先级下支持时间片的内核调度

                                             

三、系统启动

1、linux启动流程?

2、liteos启动流程?

四、内存管理

1、常见内存管理算法?linux内存管理算法?liteos内存管理算法?

linux内存管理算法:

页面置换算法:时钟策略算法的一种变体。

算法描述:基于时钟策略算法,使用一个8位的age变量。每访问一次加1,linux后台会周期性的扫描全局页池,将扫描到的每页减1,。age为0的页时最佳候选的页,age越大表明最近被使用的频率越高。

页分配:伙伴系统算法。

算法简介:伙伴分配的实质就是一种特殊的“分离适配”,即将内存按2的幂进行划分,相当于分离出若干个块大小一致的空闲链表,搜索该链表并给出同需求最佳匹配的大小。其优点是快速搜索合并(O(logN)时间复杂度)以及低外部碎片(最佳适配best-fit);其缺点是内部碎片,因为按2的幂划分块,如果碰上66单位大小,那么必须划分128单位大小的块。但若需求本身就按2的幂分配,比如可以先分配若干个内存池,在其基础上进一步细分就很有吸引力了。

算法描述:

分配内存:

1.寻找大小合适的内存块(大于等于所需大小并且最接近2的幂,比如需要27,实际分配32)

1.如果找到了,分配给应用程序。

2.如果没找到,分出合适的内存块。

1.对半分离出高于所需大小的空闲内存块

2.如果分到最低限度,分配这个大小。

3.回溯到步骤1(寻找合适大小的块)

4.重复该步骤直到一个合适的块

 

释放内存:

1.释放该内存块                                                                                                            1.寻找相邻的块,看其是否释放了。                                                                                                             2.如果相邻块也释放了,合并这两个块,重复上述步骤直到遇上未释放的相邻块,或者达到最高上限(即所有内存都释放了)

内存分配:slab分配算法。(通用数据结构缓存层)

算法描述:

 

liteos内存管理算法:

bestfit算法

tlsf算法:

slab算法:

1.1、tlsf算法详解

注:本文的大部分内容摘录自论文《TLSF: a New Dynamic Memory Allocator for Real-Time Systems》,可以通过“科学上网”访问如下链接阅读原文:http://www.gii.upv.es/tlsf/files/ecrts04_tlsf.pdf。

什么是TLSF

TLSF是Two Level SegregatedFit memory allocator的缩写,是一种动态内存分配算法。名称中有两个关键词,Segregated Fit和Two Level。

首先我们来了解什么是Segregated Fit。在内存分配算法中,空闲内存块的管理是算法的核心。根据寻找空闲内存块的策略,可以将内存分配算法分为以下几种:

  • Sequential Fit:将所有的空闲内存块,放入到一个单向/双向链表中。这是最基础的管理策略。算法非常简单,但寻找空闲内存块的效率依赖于链表的大小。
  • Segregated Fit:将所有的空闲块,放入到一组链表中,每一个链表中只包含某一个大小范围的空闲块。例如最典型的dlmalloc算法。
  • Buddy System: Segregate Fit算法的变种,具有更好的切割和合并效率,又很多变种,如Binary Buddies,Fibonacci Buddies, Weighted Buddies等。通常这类算法的内部碎片化问题比较严重。
  • Indexed Fit:通过一些高阶的数据结构来索引(Index)空闲的内存块。例如基于平衡树的“Best Fit”算法。
  • Bitmap Fit: Indexed Fit算法的变种,通过一小段内存的位图来标记对应的内存是空闲的还是使用中。

所以TLSF是一种通过一组链表来管理不同大小内存块的内存分配算法。

为什么称为Two Level?

基本的Segregated Fit算法是使用一组链表,每个链表只包含特定长度范围来的空闲块的方式来管理空闲块的,这样链表数组的长度可能会很大。如下图,TLSF为了简化查找定位过程,使用了两层链表。第一层,将空闲内存块的大小根据2的幂进行分类,如(16、32、64...)。第二层链表在第一层的基础上,按照一定的间隔,线性分段。比如2的6次方这一段,分为4个小区间【64,80),【80,96),【96,112),【112,128).每一级的链表都有一个bitmap用于标记对应的链表中是否有内存块。比如第一级别bitmap的后4bit位0100,即2的6次方这个区间有空闲块。对应的第二级链表的bitmap位0010及【80,96)这个区间有空闲块,即下面的89 Byte。

给定一个内存块的大小,确定在两级链表中的位置(f,s)的算法如下:

其中2的SLI次幂表示第二级链表的区间大小,比如上图中,区间大小为16,即2的4次方。这样大小为460字节的空闲快在链表中的位置为f=8,s=12,如下图:

TLSF适用环境

实时系统RTOS对内存分配算法有以下两个要求:

  • 内存分配/释放的执行时间可预期,可接受的。由于RTOS对指令的执行时间有严格要求,所以常常采用静态内存分配的方法,以获得一个可以预期的执行时间。
  • 内存分配算法的碎片化程度要低,这是由于RTOS往往长时间执行,碎片化程度高会导致内存分配失败。

TLSF算法的目标运行系统是:

  • 可信的执行环境,Trusted Environment,应用不会故意破坏数据或者窃取数据。
  • 有限的物理内存。
  • 没有物理MMU来支持虚拟内存。

为了在这样的环境下运行,TLSF算法使用了如下的策略:

  • Immediate coalescing,立即合并,当内存块被释放后,立即与相邻的空闲内存块合并,以获得一个更大的空闲块,插入到链表的相应位置。这样可以减少碎片化。
  • Splitting threshold,分割阈值,最小可分配的内存块大小为16字节,应用一般不会分配一些基本的数据结构,如int、char等。限定最小可分配大小为16字节,这样可以在空闲的内存块中存储一些管理信息。
  • Good-fit strategy,TLSF会尽可能的返回一个最小的、能够满足需求的内存块。
  • Same strategy for all block sizes,对于不同大小的内存请求,TLSF只有一个分配策略,实现相对简单,执行时间可以预期。相应的dlmalloc根据所请求的内存大小不同,有多达4种内存分配策略。
  • Memory is not cleaned-up,分配个应用的内存没有被请0.

TLSF的特点在于:

  • 可以预期的分配执行时间,无论对于多达的内存分配请求,TLSF可以在限定的时间内完成分配。
  • 碎片化程度低。

参考博客:https://blog.csdn.net/sunao2002002/article/details/50611838

2、常见页面替换算法?

OPT 最佳:置换下次访问距当前时间最长的那些页。优点:导致最少的缺页中断,不过难以实现。

LRU 最近最少使用:置换内存中上次使用距当前最远的页。难以实现。

FIFO :该策略把分配给进程的页框看做是一个循环缓冲区,按循环方式移动页。

时钟策略算法:所有页框可以想象成在一个环中。每个页框有个附加使用位。当某页首次装入时,该位置1。当该页随后被访问到时,使用位也置1。用于置换的候选页框集合看做缓冲区,且有一个指针与之关联。当一页被置换时该指针被设置成指向缓冲区的下一个页框。当需要置换一页时,系统扫描缓冲区,查找使用位为0的页框。每遇到一个使用位为1的页框则使用位置为0。如果在扫描时,所有页框使用位都为0则选择遇到的第一个页框。如果所有的页框使用位都为1则指针扫描一圈,将所有使用位置0,并停留在最初的位置上,置换该页框中的页。

3、虚拟内存分页和虚拟内存分段的定义?

分页: 内存被划分为许多大小相等的页框,每个进程被划分为许多大小与页框相等的页,在装入进程时,

将驻留页装入到内存中不一定连续的某些页框中,非驻留页在以后需要时自动调入内存。

优势: 没有外部碎片,支持更多道数的多道程序设计,巨大的虚拟地址空间。

缺陷: 复杂的内存管理开销。

分段: 每个进程被划分为许多段,在装入进程时,把驻留段装入到内存中不一定连续的动态分区中,非驻留段在以后需要时自动调入内存。

优势: 没有内部碎片,支持更多道数的多道程序设计,巨大的虚拟地址空间,支持保护和共享。

缺陷: 复杂的内存管理开销。

 

五、中断

                                       

1、为什么中断里不能用printf?

会导致死锁,引用STDOUT全局变量时采用了锁机制,而锁机制会导致阻塞,阻塞是不可重入的真子集。

假如一个任务或中断处理程序调用了printf,被另一个高优先级中断打断,该中断中也调用printf,那么就会形成死锁。

2、软件定时器实现方法和原理?

时间轮法

十四、ARM汇编

1、mcr与mrc指令

十五、C语言

1、volatile 的作用?

2、const的作用?

十六、C++语言

二十一、面试时应该提些什么问题?

1、贵公司的薪酬如何分布?

2、贵公司的上升渠道能否介绍下?

3、贵公司的技术实力及专家实力能否介绍下?

4、贵公司的管理制度能否介绍下?

猜你喜欢

转载自blog.csdn.net/chichi123137/article/details/80275825