【一】操作系统原理

1.进程和线程的相关题

  1. 进程:进程是系统进行资源分配和调度的一个独立单位,是系统中的并发执行的单位。
  2. 线程:线程是进程的一个实体,也是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位,有时又被称为轻量级进程。
  3. 进程是资源分配的最小单位,而线程是CPU调度的最小单位;创建进程或撤销进程,系统都要为之分配或回收资源,操作系统开销远大于创建或撤销线程时的开销;不同进程地址空间相互独立,同一进程内的线程共享同一地址空间。一个进程的线程在另一个进程内是不可见的;进程间不会相互影响,而一个线程挂掉将可能导致整个进程挂掉。
  4. 进程的内存空间共享,每个线程都可以使用这些共享内存。一个线程在使用共享内存的时候,其他线程需要等待结束才能使用这块内存。因此线程进去之后记得关门(上锁),上了锁,其他线程想进来发现是上锁了,那就等锁打开后再进去,这就叫做互斥锁,防止多个线程同时读写某一块内存区域。
  5. 如果以多进程的方式运行,那么允许多个任务同时运行。
  6. 如果以多线程的方式运行,那么允许将单个任务分成不同的部分运行。
  7. 为了防止进程/线程之间产生冲突和允许进程之间的共享资源,需要提供一种协调机制。

 2.提到高并发、分布式,就不得不想起多线程,那么多线程一定比单线程效率高?

  1. Memcache是多线程模型而Redis是单线程模型。
  2. 采用多线程多核效果更好,但是多线程对CPU,内存等都要求比较高,如果存在线程的上下文切换过于耗时,互斥时间太久,效率反而会低。

3.多线程与多进程的应用场景

  1. 多线程的优点:更加高效的内存共享:多进程下内存共享不便;较轻的上下文切换:因为不用切换地址空间,CR3寄存器和清空TLB。
  2. 多进程的优点:各个进程有自己内存空间,所以具有更强的容错性,不至于一个集成crash导致系统崩溃;具有更好的多核可伸缩性,因为进程将地址空间,页表等进行了隔离,在多核的系统上可伸缩性更强。

4.如何提升多线程的效率?

  1. 尽量使用池化技术,也就是线程池,从而不用频繁的创建,销毁线程。
  2. 减少线程之间的同步和通信。
  3. 通过Huge Page的方式避免产生大量的缺页异常。
  4. 避免需要频繁共享写的数据。

5.为什么有了进程,还要有线程呢?

  1. 为了提高系统资源的利用率和系统的吞吐量,通常进程可让多个程序并发的执行,但是也会带来一些问题。进程如果在执行的过程被阻塞,那这个进程将被挂起,这时候进程中有些等待的资源得不到执行;进程在同一时间只能做一件事儿。
  2. 基于以上的缺点,操作系统引入了比进程粒度更小的线程,作为并发执行的基本单位,从而减少程序在并发执行时所付出的时间和空间开销,提高并发性能。

6.对并发和并行的理解?

  1. 并发:在一个时间段中多个程序(人物)都启动运行在同一个处理机中。
  2. 并行:假设目前A,B两个进程,两个进程分别由不同的CPU管理执行,两个进程不抢占CPU资源且可以同时运行,这叫做并行(同一时间点内
  3. 两者区别在于是否"同时"发生。是在一段时间同时发生还是多个事情在同一个时间点同时发生。

7.进程间的通信方式有哪些?

1.管道:在学习Linux基本命令使用的时候,我们经常通过多个命令的组合来完成我们的需求。比如说我们想知道如何查看进程或者端口是否在使用,会使用下面的这条命令。

netstat -nlp | grep XXX  这里的"|"实际上就是管道的意思。"|"前面部分作为"|"后面的输入,很明显是单向的传输,这样的管道我们叫做"匿名管道",自行创建和销毁。既然有匿名管道,应该就有带名字的管道"命名管道"。如果你想双向传输,可以考虑使用两个管道拼接即可。

管道通信方式的点:简单,我们平时经常使用以致于都不知道这是管道。

管道通信方式的缺点:效率很低,因为假设现在有AB两个进程,A进程将数据写入管道,B进程需要等待A进程将信息写完以后才能读出来,所以这种方案不适合频繁的通信。

2.消息队列:消息队列在发送数据的时候,按照一个个独立单元(消息体)进行发送,其中每个消息体规定大小块,同时发送方和接收方约定好消息类型或者正文的格式。

消息队列的优点:在管道中,其大小受限且只能承载无格式字节流的方式,而消息队列允许不同进程以消息队列的形式发送给任意的进程。

消息队列的缺点:数据太大时,需要拷贝的时间也就越多。

3.共享内存:每个进程都有自己的虚拟内存空间,不同的进程映射到不同的物理内存空间。那么我们可以申请一块虚拟地址空间,不同进程通过这块虚拟地址空间映射到相同的物理地址空间。这样不同进程就可以及时感知进程做了什么,就不需要再拷贝来拷贝去。通过shmget创建一份共享内存,并可以通过ipcs命令查看我们创建的共享内存。此时如果一个进程需要访问这段内存,需要将这个内存加载到自己虚拟地址空间的一个位置,让内核给它一个合法地址。使用完毕接触板顶并删除内存对象。

共享内存的缺点:许多进程都共享这块内存,如果同时都往里面写内容,难免会出现冲突的现象,比如A进程写了数字5,B进程同样的地址写了6就直接给覆盖了,这样就不友好了?

4.信号量:为了防止冲突,我们得有个约束或者说一种保护机制。使得同一份共享的资源只能一个进程使用,这里就出现了信号量机制。信号量实际上是一个计数器,这里需要注意下,信号量主要实现进程之间的同步和互斥,而不是存储通信内容。信号量定义了两种操作,p操作和v操作,p操作为申请资源,会将数值减去M,表示这部分被他使用了,其他进程暂时不能用。v操作是归还资源操作,告知归还了资源可以用这部分。

5.信号:在操作系统中,不同信号用不同的值表示,每个信号设置相应的函数,一旦进程发送某一个信号给另一个进程,另一进程将执行相应的函数进行处理。也就是说把可能出现的异常等问题准备好,一旦信号产生就执行相应的逻辑即可。

6.套接字:上面的几种方式都是单机情况下多个进程的通信方式,如果我想和相隔几千里的计算机通信怎么办?这就需要套接字socket,生活中极常见,因为我们天天请求浏览器给予的响应。

8.进程的调度算法有哪些?

调度算法是指:调度程序是内核的重要组成部分,决定着下一个要运行的进程。那么根据系统的资源分配策略所规定的资源分配算法。

  1. 先来先服务调度算法:如同队列的先进先出特性,每一次的调度都从队列中选择最先进入队列的投入运行。
  2. 时间片轮转调度法:如果进程在当前的时间片运行结束,直接将进程从队列移除。如果进程在这个时间片跑完都没有结束,进程变为等待状态,放在进程尾部直到所有进程执行完毕。
  3. 短作业优先调度算法:「短作业」意味着执行时间比较短,「优先」代表执行顺序。
  4. 最短剩余时间优先:最短剩余时间是针对最短进程优先增加了抢占机制的版本。在这种情况下,进程调度总是选择预期剩余时间最短的进程。当一个进程加入到就绪队列时,他可能比当前运行的进程具有更短的剩余时间,只要新进程就绪,调度程序就能可能抢占当前正在运行的进程。像最短进程优先一样,调度程序正在执行选择函数是必须有关于处理时间的估计,并且存在长进程饥饿的危险。
  5. 高响应比优先调度算法:有响应之前应该会有请求,相当于是请求+响应+优先,算是一种综合的调度算法。也就是它结合了短作业优先,先来先服务以及长作业的一些特性。首先来说短作业优先。等待时间我们假设相等,服务时间很短,这样的话短作业就会有更高的优先权。再来看先来先服务。假设服务时间相同,先来的自然等待时间较长,优先级越高。上面说长作业很可能因为等待时间过长,容易饿死。
  6. 优先级调度算法:优先级调度算法每次从后备作业队列中选择优先级最髙的一个或几个作业,将它们调入内存,分配必要的资源,创建进程并放入就绪队列。在进程调度中,优先级调度算法每次从就绪队列中选择优先级最高的进程,将处理机分配给它,使之投入运行。

9.同步、异步、阻塞、非阻塞的概念

  1. 同步异步,阻塞非阻塞是两个不同层面的问题,一个是operation层面,一个是kernal层面。同步异步最大的区别在于是否需要底层的响应再执行。阻塞非阻塞最大的区别在于是否立即给出响应。
  2. 同步:当一个同步调用发出后,调用者要一直等待返回结果。通知后,才能进行后续的执行。
  3. 异步:当一个异步过程调用发出后,调用者不能立刻得到返回结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。
  4. 阻塞:是指调用结果返回前,当前线程会被挂起,即阻塞。
  5. 非阻塞:是指即使调用结果没返回,也不会阻塞当前线程。
  6. 形象比喻:
  • 小Q去钓鱼,抛完线后就傻傻的看着有没有动静,有则拉杆(同步阻塞);
  • 小Q去钓鱼,拿鱼网捞一下,有没有鱼立即知道,不用等,直接就捞(同步非阻塞);
  • 小Q去钓鱼,这个鱼缸比较牛皮,扔了后自己就打王者荣耀去了,因为鱼上钩了这个鱼缸带的报警器会通知我。这样实现异步(异步非阻塞)

10.产生死锁的原因?

  1. 由于系统中存在一些不可剥夺资源,而当两个或两个以上进程占有自身资源,并请求对方资源时,会导致每个进程都无法向前推进,这就是死锁。
  2. 原因一:竞争资源
  3. 原因二:进程推进顺序不当。例如:进程 A 和 进程 B 互相等待对方的数据。
  • 例如:系统中只有一台打印机,可供进程 A 使用,假定 A 已占用了打印机,若 B 继续要求打印机打印将被阻塞。系统中的资源可以分为两类:
  • 可剥夺资源:是指某进程在获得这类资源后,该资源可以再被其他进程或系统剥夺,CPU和主存均属于可剥夺性资源;
  • 不可剥夺资源当系统把这类资源分配给某进程后,再不能强行收回,只能在进程用完后自行释放,如磁带机、打印机等。

11.怎么避免死锁?

  1. 银行家算法:当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求量则按当前的申请量分配资源,否则就推迟分配。当进程在执行中继续申请资源时,先测试该进程已占用的资源数与本次申请资源数之和是否超过了该进程对资源的最大需求量。若超过则拒绝分配资源。若没超过则再测试系统现存的资源能否满足该进程尚需的最大资源量,若满足则按当前的申请量分配资源,否则也要推迟分配。
  2. 安全序列:是指系统能按某种进程推进顺序(P1, P2, P3, …, Pn),为每个进程 Pi 分配其所需要的资源,直至满足每个进程对资源的最大需求,使每个进程都可以顺序地完成。这种推进顺序就叫安全序列【银行家算法的核心就是找到一个安全序列】
  3. 系统安全状态:如果系统能找到一个安全序列,就称系统处于安全状态,否则,就称系统处于不安全状态。
  4. 资源分配图:用来描述系统死锁。
  5. 死锁定理:s为死锁状态的充分条件是:当且仅当s状态的资源分配图是不可完全简化的。

 12.怎么解除死锁?

  1. 资源剥夺:挂起某些死锁进程,并抢占它的资源,将这些资源分配给其他死锁进程(但应该防止被挂起的进程长时间得不到资源);
  2. 撤销进程:强制撤销部分、甚至全部死锁进程并剥夺这些进程的资源(撤销的原则可以按进程优先级和撤销进程代价的高低进行);
  3. 进程回退:让一个或多个进程回退到足以避免死锁的地步。进程回退时自愿释放资源而不是被剥夺。要求系统保持进程的历史信息,设置还原点。

13.什么是缓冲区溢出?有什么危害?

缓冲区溢出指当计算机向缓冲区内填充数据时超过了缓冲区本身的容量,溢出的数据覆盖在合法数据上。

14.物理地址、逻辑地址、线性地址

  1. 物理地址:它是地址转换的最终地址,是内存单元真正的地址。如果采用了分页机制,那么线性地址会通过页目录和页表的方式转换为物理地址。如果没有启用则线性地址即为物理地址。
  2. 逻辑地址:在编写c语言的时候,通过&操作符可以读取指针变量本身的值,这个值就是逻辑地址。实际上是当前进程的数据段的地址,和真实的物理地址没有关系。只有当在Intel实模式下,逻辑地址==物理地址。我们平时的应用程序都是通过和逻辑地址打交道,至于分页,分段机制对他们而言是透明的。逻辑地址也称作虚拟地址。
  3. 线性地址:线性地址是逻辑地址到物理地址的中间层。我们编写的代码会存在一个逻辑地址或者是段中的偏移地址,通过相应的计算(加上基地址)生成线性地址。此时如果采用了分页机制,那么吸纳行地址再经过变换即产生物理地址。在Intelk 80386中地址空间容量为4G,各个进程地址空间隔离,意味着每个进程独享4G线性空间。多个进程难免出现进程之间的切换,线性空间随之切换。基于分页机制,对于4GB的线性地址一部分会被映射到物理内存,一部分映射到磁盘作为交换文件,一部分没有映射。

15.页面置换算法有哪些?

请求调页,也称按需调页,即对不在内存中的“页”,当进程执行时要用时才调入,否则有可能到程序结束时也不会调入。而内存中给页面留的位置是有限的,在内存中以帧为单位放置页面。为了防止请求调页的过程出现过多的内存页面错误(即需要的页面当前不在内存中,需要从硬盘中读数据,也即需要做页面的替换)而使得程序执行效率下降,我们需要设计一些页面置换算法,页面按照这些算法进行相互替换时,可以尽量达到较低的错误率。常用的页面置换算法如下:

  1. 先进先出置换算法(FIFO)先进先出,即淘汰最早调入的页面。
  2. 最佳置换算法(OPT)选未来最远将使用的页淘汰(一种最优的方案)缺页数最小。
  3. 最近最久未使用算法(LRU)即选择最近最久未使用的页面予以淘汰。
  4. 时钟置换算法(Clock)也叫最近未用算法 NRU(Not RecentlyUsed)。该算法为每个页面设置一位访问位,将内存中的所有页面都通过链接指针链成一个循环队列。
  5. 改进型clock置换算法
  6. 最不常用算法(LFU)当一个缺页中断发生时,选择访问次数最少的那个页面,并淘汰之。

16.IO密集型和CPU密集型

CPU密集型通常需要执行大量的CPU运算任务,这个时候保持线程数和CPU核数相当即可,不然容易更多的线程上下文切换。再web系统开发中,更多的可能是对于数据库的查询等IO操作,此时CPU会空闲一段下来。

(欢迎您的意见和建议,感谢支持!!!❤❤❤)

猜你喜欢

转载自blog.csdn.net/weixin_42067873/article/details/111942188