操作系统部分
线程调度算法
尴尬。。。第一遍没听懂,还寻思线程调度是啥。。。还让面试官解释了一遍,可是一般不都是说进程调度吗
- FCFS: 先来先服务,但是如果前边的是长任务就后边的短任务一致等待
- 多级反馈队列
- 时间片轮转
- 短作业优先: 短作业优先,但是当有长作业的时候,就会导致短作业等待时间过长。
补充
- 多级反馈队列
- 线程被分配到多个优先级队列,每个队列对应不同的时间片或调度策略。
- 高优先级的队列先运行,低优先级队列后运行。
- 如果线程未完成且耗尽时间片,则会被移动到更低优先级的队列中(动态调整优先级)。
- 可以结合 时间片轮转 或其他策略在每个队列中执行。 5) 实现复杂,但是调度灵活
- 时间片轮转
- 每个线程被分配一个固定的时间片(时间片长度可以调节), 时间片用完后,如果线程未完成,则被放回队列尾部等待下一轮调度。
- 时间片选择会影响到效率
- 优先级调度
- 每个线程分配一个优先级,调度时优先调度高优先级
- 分为抢占式和非抢占式。非抢占式,需要等待当前任务执行结束主动放弃CPU;抢占式,如果有更高优先级的线程到达,当前执行线程会被阻塞
- 最短剩余事件优先
- 如果新任务的预期运行时间小于当前任务剩余执行时间,则新任务优先执行
- 难以准确预测任务运行时间
如何设计一个时间片轮转算法
回答的不太好,说可以先预处理,对规模很大的任务做一个标记,其他任务使用平均,规模很大的任务自动调整 补充(GPT提供):
- 设计一个FIFO的任务队列,每个任务分配固定时间片
- 按照队列顺序执行任务,如果任务完成,则继续执行
- 大任务耗费时间片比较多,可能阻塞小任务,小任务多次切换浪费时间,可以与处理任务,识别规模大的任务,预先为其分配动态调整的时间,避免频繁上下文切换
- 对小任务使用固定时间片
线程安全
- 互斥锁:避免数据竞争,同一时刻只能有一个线程拿到锁的所有权,需要注意避免死锁
- 信号量:通过计数器的方式,控制可访问资源的数量
- 原子变量:硬件上可以通过总线锁的方式,保证同一个时刻只有一个线程可以读写数据;又扯了一下C++的内存序,内存屏障。。。
- 自旋锁:当等待的事件明显少于加锁的事件,可以使用自旋锁,自选锁就是一直尝试获取锁,直到成功拿到
- 读写锁:同一时刻可以有多个线程同时读,但是写只能有一个线程写,写完后其他线程才能读
- 互斥锁与信号量的区别:线程需要拿到锁才能执行,信号量是计数器大于0,线程就可以消耗资源
补充:
- 递归锁:递归锁,递归调用,线程安全,但效率不高,因为每次递归都需要加锁,所以递归锁适合在函数调用深度比较深的场景。
- C++内存序:内存序保证了多线程读写操作的可见性和顺序性。原子性虽然保证了操作不可分割,但是不能保证操作的执行顺序,内存序扩展了原子性的概念。 即使是原子操作,如果使用了松散内存序,也可能导致其他线程观察到非预期的顺序。
- C++内存屏障:内存屏障阻止了指令重排,C++的
atmoc隐式包含了内存屏障,保证正确性 - 自旋锁:自选锁有可能导致活锁问题, 活锁:线程忙等待,彼此干扰
- 读写锁: 写操作可能会被长时间阻塞
- 条件变量:通过条件变量,实现内存同步
Linux内存管理
尴尬,答成内存分配了。。。再次回答了
- 页式: 页面固定大小,页内地址与物理页地址一致,通过页表查找物理页框号,页表存储页号到物理页框的映射关系。现代计算机使用TLB快表加快页表项查询速度
- 段式:段大小不固定,与程序段的概念类似,一段程序存储在一个段内,逻辑地址由段号和段内地址组成
- 段页式:综合段式、页式特点,有段号,页号,页内偏移。进一步将段划分为固定大小的页
- 虚拟内存往往比可用的实际内存大,如果访问的页不在内存怎么办? 触发缺页中断,通过页面调度算法如FIFO,LRU等算法调出一个页面,将新数据加载到页内 补充:
- 不常用的资源会保存在磁盘上。
- 缺页中断的过程
- 触发缺页中断
- 查找所需页是否在磁盘,如果不存在发生段错误,如果存在,使用页面置换算法选择一个页面替换,
- FIFO 选择最早加载的页面进行替换;
- LRU 选择最近最少使用的页面替换
- LFU 选择使用频率最少的页面替换
- OPT 选择最近最远使用的页面替换
设计模式
回答掌握的只有单例,其他的只是概念上知道一些
- 单例模式: 将构造设置为私有的,拷贝构造拷贝赋值删除,可以将析构设置为public的,也可以将析构设置为私有的通过手动指定一个删除器,管理。C++11提供了
call_once保证多线程只会实例化一次,也可以通过两次判断空的方式,保证只实例化一次 - 观察者模式:观察者模式可以观察到被观察者的状态,被观察者状态更新时,观察者可以同步更新
- 工厂模式:需要有一个抽象基类,其他类继承实现具体的类。 补充:
- 观察者模式:当被观察对象(Subject)的状态发生改变时,自动通知所有依赖的观察者(Observer)。
- 工厂模式:抽象基类提供同一接口,工厂类根据传入参数返回不同具体类的实例。
项目相关
- 对客户端,后端的看法
- 下一步如何优化
手撕 最大值路径
|
|