计算机操作系统

1、进程、线程、协程的区别

线程和进程的区别

  1. 拥有资源

进程是资源分配的基本单位,但是线程不拥有资源,线程可以访问隶属进程的资源

  1. 调度

线程是独立调度的基本单位,进程是一个执行流,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位

  1. 系统开销

由于创建或撤销进程时,系统都要为之分配或回收资源,如:内存空间IO设备等,所以付出的开销远大于创建或撤销线程时的开销。类似的,在进行进程切换时,涉及当前执行进程CPU环境的保存及新调度进程CPU环境的设置,而线程切换只需要保存和设置较少量寄存器内容,开销很小

  1. 通信方面

线程间可以通过直接读写同一进程中的数据进行通信,但是进程通信需要借助IPC

协程与线程的区别

协程是一种用户太的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下问和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切换回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核的开销,可以不枷锁的访问全局变量,所以上下文切换的非常快

  • 一个线程可以有多个协程,一个进程也可以单独拥有多个协程
  • 线程进程都是同步机制,而协程则是异步
  • 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态

2、进程间通信的方法

消息队列共享内存无名管道命名管道信号量socket

  • 父子进程管道pipe:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有血缘关系的进程间使用。进程间的血缘关系通常是指父子进程关系
  • 命名管道FIFO:有名管道也是半双工的通信方式,但是它允许无亲缘的关系进程间的通信
  • 消息队列MessageQueue:消息队列是由消息的链表,存放在内核中并由消息队列标志符标志。消息队列客服了信号传递信号量少、管道只能承载无格式字节流以及缓冲区大小受限等缺点、
  • 共享存储:共享内存就是映射一段能 被其他进程锁访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问,共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的,它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步通信
  • 信号量Semaphore:信号量是一个技术器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也可访问该资源。因此,主要作为进程间以及同一进程间不同线程之间的同步手段
  • 套接字(Socket):也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器之间的进程通信
  • 信号(signal):信号是一种比较复杂的通信方式,用于通知接受进程某个事件已经发生

3、进程调度算法

进程调度任务过程

  • 首先保存当前进程的处理机的现场信息
  • 按照算法选取进程
  • 把处理器分配给进程(将选中进程的进程控制块内有关处理机现场的信息装入处理机相应寄存器中,进程控制处理机,使之从上次的断电常处恢复运行)

不同环境的调度算法目标不同,因此需要针对不同环境来讨论调度算法

操作系统管理了系统的有限资源,当有多个进程(或多个进程发出的请求)要使用这些资源时,因为资源的有限性,必须按照一定的原则选择进程(请求)来占用资源。这就是调度。目的是控制资源使用者的数量,选取资源使用者许可占用资源或占用资源。

进程调度算法

1、先来先服务和短作业(进程)优先调度算法

  1. 先来先服务(FCFS)

先来先服务调度算法是一种最简单的调度算法,该算法即可用于作业调度,也可用于进程调度。当在作业调度中采用该算法时,每次调度都是从后备作业队列中选择一个或多个最先进入该队列的作业,将他们调入内存,为他们范围内配资源,创建进程,然后放入就绪队列。在进程调度中采用FCFS算法时,则每次调度是从就绪队列中选择一个最先进入该队列的进程,为之分配处理机,使之投入运行。该进程一直运行都完成或发生某事件而阻塞后才放弃处理机

优点:易于实现,且相对公平

缺点: 比较有利于长进程,而不利于短进程

  1. 短进程优先shortest job first (SJF)

按估计运行时间最短的顺序进行调度。短作业优先(SJF)的调度算法是从后备队列中选择一个或者若干个运行时间最短的作业,将他们调入内存运行。而段进城优先(SPF)调度算法则从就绪队列中选出一个估计运行 时间最短 的进程,将处理机分配给它,使它立即执行并一直执行到完成,或发生某事件而被阻塞放弃处理机时在重新调度

优点:平均周转时间段,进程等待的时间缩短,可以增大系统的吞吐量

缺点:难以准确估计进程执行时间,开销较大;不利于长进程,有可能“饥饿”现象。

  1. 最短剩余时间优先shortest remianing time next (SRTN)

按估计剩余时间最短的顺序进行调度

2、高优先权调度算法

为了照顾紧迫型作业,使之在进入系统后便获得优先处理,引入了最高优先权优先(FPF)调度算法。当把该算法用于作业调度时,系统将从后备队列中选择若干个优先权最高的作业装入内存。当用于进程调度时,该算法是把处理机分配给就绪队列中优先权最高的进程,这时,又可进一步把该算法分成如下两种:

  1. 非抢占式优先权算法

在这种方式下,系统一旦把处理机分配给就绪队列中优先权最高的进程后,该进程便一直执行下去,直至完成;或因发生某件事件使得该进程放弃处理机时,系统方可把处理机重新分配给另一优先权最高的进程。这种调度算法主要用于批处理算法中,也可用于某些对实时性要求不严的实时系统

  1. 抢占式优先权调度算法

在这种方式下,系统同样把处理机分配给优先权分配给优先权最高的进程,使之执行。但在其执行期间,只要出现另一个优先权限更高的进程,优先权调度程序就立即停止当前进程(源有限权最高的进程)的执行,重新将处理机分配给新到的优先权最高的进程。显然,这种抢占式的优先权调度算法能够更好的满足紧迫任务的要求,孤儿常用于要求比较严格的实时系统中,以及对性能要求比较高的批处理和分时系统中

3、高响应比优先调度算法

在批处理系统中,短作业优先算法是一种比较好的算法,其主要的不足之处是厂作业的运行得不到保障。如果我们能为每个作业引入前面锁述的动态优先权,并使得作业的优先级随着等待时间的增加而提高,则长作业在等待一定的时间后,必然有机会分配到处理机

优先级=(服务时间+等待时间)/服务时间=1+等待时间/服务时间

  • 如果作业的等待时间相等,则要求服务时间越短,其优先权越高,因而该算法有利于短作业
  • 当要求的服务时间相同时,作业的优先权限取决于等待时间,等待时间越长,其优先权越高,因而它实现的是先来先服务
  • 对于场作业,作业的优先级可以随着等待时间的增加而提高,当器等待时间足够长时,其优先级便可升到很高,从而也可获得处理机。简言之,该算法即可照顾了短作业,又考虑了作业达到后的先后次序,不会使得场作业长期得不到服务。因此该算法实现了一种较好的折中。当然,在利用该算法时,每要进行调度之前,都需要做响应比的计算,这会增加系统的开销

4、基于时间片的轮转调度算法

交互式系统由大量的用户交互操作,在该系统中调度算法的目标是快速的进行响应

  1. 时间片轮转

将所有就绪线程按照FCFS的原则排成一个队列,每次调度时,把CPU时间分配给队首进程,该进程可以执行一个时间片,时间片轮转算法的效率和时间片的大小有很大的关系

因为进程切换都要保存进程的信息并且载入新进程的信息,如果时间片太小,会导致进程切换的太频繁,在进程切换上就会花过多时间。而如果时间片过长,那么实时性就不能得到保障

  1. 多级反馈队列(比较有限调度算法)

可以将这种调度算法看成是时间片轮转算法和优先级调度算法的结合

首先。该算法设置多个就绪队列,并未各个队列赋予不同的优先级。第一个队列的优秀级最高,第二个队列次之,其余各个对列的优先权逐个降低。该算法赋予各个队列中进程执行时间片的大小也各部相同,在优先权越高的队列中,为每个进程所规定的执行时间片就越小。

当然,当一个新进程进入内存后,首先将它放入第一队列的末尾,按照FCFS的原则等待调度。当轮到该进程执行时,如它能在该时间片内完成,便可准备撤离系统;如果它在一个时间片结束时尚未完成,调度程序则会将该进程转入第二队列的末尾,再同样的按照FCFS原则等待执行;如果它在第二个队列中运行一个时间片后仍未完成,再以次将它放入第三队列,。,,,,,,如此下起雨,当一个场作业(进程从第一队列依次降到第n队列后,在第n队列便采取按时间片轮转的方式运行)

最后,仅当第一队列空闲时,调度程序才调度第二队列中的进程运行:仅当地1~(i-1)队列均为空时,才会调度第i队列中的进程运行。如果处理机正在第i队列中摸一个服务进程时又有新进程进入优先权较高的队列,则此时新进程将抢占正在运行进程的处理机,基友调度程序把正在运行的程放回到第i队列末尾,把处理机分配福给新到的高优先权进程

4、死锁和处理方法

产生死锁必要条件(java死锁的条件也是这些,引申到java并发)

互斥每个资源要么已经分配给一个进程,要么就是可用的

占有和等待:已经得到了某个资源的进程可以再请求新的资源

不可抢占:已经分配给一个进程的资源不能强制性的抢占,它只能被占有它的进程显示的释放

环路等待:有两个或者两个以上的进程组成一条环路,该环路中的每个进程都在等大爱下一个进程所占有的资源

c处理方法

鸵鸟策略:处理死锁的问题的办法仅仅是忽略它

死锁检测与死锁恢复:不的视图阻止死锁,而是当检查死发生的时候,采取措施进行恢复,利用抢占恢复,回滚恢复,回滚恢复时,通过杀死进程恢复

死锁预防:破坏死锁必要条件

死锁避免:程序运行期间避免死锁

社么是活锁

活锁恰恰与死锁相反,死锁是大家都拿不到资源都占用对方的资源,而活锁是拿到资源却又相互释放不执行。当多线程出现了相互礼让,都主动将资源释放给别的线程使用,这样在这个资源在多个线程之间跳动而右得不到执行,这就是活锁

5、内存管理

cankao

  1. Linux采用虚拟内存技术

    • 虚拟内存,物理内存,页表,内存管理单元

      ​ 操作系统将内存抽象成虚拟地址空间,每个程序拥有自己的地址空间,这个地址空间被分隔成多个块,每一块称为一页,这些页被映射到物理内存(页框),同时,就必须把页吗和存放该页映像的页框填入一个叫 页表的表项中,其中,页表的表项中设置一些访问控制字段,用于指明对应页面中的内容允许何种操作,从而禁止非法访问。

      ​ 内存管理单元(MMU)g管理着虚拟内存地址和物理内存 的转换,其中页表(Page table)存储着页(程序地址空间)和页框(物理内存空间的)映射表

      虚拟内存作用

      • 内存完整性:每个进程都自认为自己获取的内存是一块连续的地址
      • 安全:操作系统在页表的各个项目上添加各种访问权限标志位
      • 数据共享:通过虚拟内存更容易实现内存和数据的共享
      • SWAP:虚拟内存可以帮进程“扩称”内存。Linux提出SWAP的概念,Linux中可以使用SWAP分区,在分配物理内存时,但可用内存不足时,将暂时不用的内存数据线放到磁盘上,让有需要的进程先使用,等进程再需要使用这些数据时,在将这些数据加载到内存中,通过这种“交换”技术,Linux可以让进程使用更多的内存

      2、请页和交换

      请页

      访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存(请求调页功能)

      当处理器视图访问一个虚存月面时,首先到也表中去查询该页是否已映射到物理页框中,并记录在页表中,如果在,则MMU会把页吗转换成页框吗;如果不在,MMU就会通知操作系统:发货所能了一个页面访问错误(页面错误),接下来系统会启动所谓的“请页”机制,即调用响应的操作系统函数,判断该虚拟地址是否为有效地址。

      如果是有效地址,就从虚拟内存中将改地址指向的页面读入到内存中的一个空闲也框中,并在页表中添加上对应的表项,最后处理器将从发生页面错误的地方重新开始运行;如果是无效地址,则表明进程在视图访问一个不存在的虚拟地址,此时系统将终止此次访问。

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yyGMHHV4-1583296131395)(images/01.png)]

      交换(SWAP)

      内存空间不够时,将内存中暂时用不到的信息换出到外存(页面置换功能)

      请页成功后,存在已没有空闲物理页框的情况,启动所谓的交换机制,即调用响应的内核操作函数,在物理页框中寻找一个当前不在使用或者近期可能不会用到的页面所占据的页框。找到后,就把其中的页移出,以装载新的页面。如果该页未被修改过,则删除它;如果该页曾经被修改过(“脏页""),则系统必须将该页写会磁盘。

      3、页面置换算法

      页面置换算法:就是要选出合适的一个物理页框,将其淘汰或者存储到磁盘上,使得置换效率最高

      置换算法有

      • 最佳置换算法(OPT,Optimal) :每次选择淘汰的页面将是以后永不使用,或者在最长时间内不再被访问的页面,这样可以保证最低的缺页率。无法实现

      • 先进先出置换算法(FIFO) :每次选择淘汰的页面是最早进入内存的页面 实现方法:把调入内存的页面根据调入的先后顺序排成一个队列,需要换出页面时选择队头页面队列的最大长度取决于系统为进程分配了多少个内存块。

      • 近期最久未使用到算法(LRU)

      • clock置换算法NRU

      • 页面缓冲算法PBA

      • 近期最少使用算法 LFU

        和缓存淘汰策略类似,可以将内存看成磁盘的缓存。在缓存系统中,缓存的大小有限,当有心的缓存到大时,需要淘汰一部分已经存在的缓存,这样才有空间存放新的缓存数据。

        LRU(LRU缓存淘汰算法)为了实现LRU,需要在内存中维护一个一个所有页面的链表(leetcode中有个体,实现LRU,利用HAShMap+双向链表,map的key值表示这链表中每个节点的位置)。当一个页面被访问是,将这个页面移动到链表的表头,这样就能好保证链表的表位的页面是醉酒未被访问的

      4、加快分页过程

      如何提高细腻和物理地址映射速度(块表)?

      系统一旦访问了某一个页,那么系统就会在一段时间内稳定的工作在这个页上。所以,为了提高访问页表的速度,系统还配备了一组账号能容纳一个页表的硬件寄存器,这样当系统在访问虚存时,就首先到这组硬件寄存器中访问,系统速度就快多了。这组存放当前页表的寄存器叫做块表。

      如果页表很大怎么解决?

      采用多级页表,对页表也进行分页存储,在程序运行时只把需要的页复制到内存,而暂时不需要的页就让他流在辅存中

      5、分页和分段的比较

      对程序员的透明性:分页透明,但是分段需要程序员显示划分每个段

      对地址空间的维度:分页是一位地址空间,分段是二维的程序员在标志一个地址时,既需要给出段名,又需要给出段内地址

      大小是否可以改变:页的大小是不变的,段的大小可以动态改变

      出现的原因:分页主要用于实现虚拟内存,从而获得更大的地址空间;分段主要是为了使得程序和数据可以被划分为逻辑上独立的地址空间并且有助于共享和保护

      **

6、IO管理

IO网络面模型

IO多路复用技术

IO模型

第一步通常涉及等待数据从网络到达,当所等待数据到达时,它被复制到内核中的某个缓冲区。第二步就是把数据从内核缓冲区复制到应用进程缓冲区中

对于一个应用程序即一个操作系统进程来说,它既有内核空间(与其他进程共享),也有用户空间(进程私有),它们都是处于虚拟地址空间中。用户进程是无法访问内核空间的,它只能访问用户空间,通过用户空间去内核空间复制数据,然后进行处理。

阻塞狮IO (同步io)

发起请求就一直等待,直到数据返回。好比你去商场试衣间,里面有人,那你就一直在门外等着。(全程阻塞)

非阻塞式IO

应用进程可以继续执行,但是需要不断的执行系统调用来获知I/O是否完成,这种方式称为轮询(polling)

I/O复用(select,poll,epoll)

单个进程具有处理多个I/o时间的能

信号驱动(SIGIO)

事先发出一个请求,当有数据后会返回一个标识回调,这时你可以去请求数据。好比银行排号,当叫到你的时候,你就可以去处理业务了(复制数据时阻塞)。

异步IO

发出请求就返回,剩下的事情会异步自动完成,不需要做任何处理。好比有事秘书干,自己啥也不用管。

五种IO的模型:阻塞IO、非阻塞IO、多路复用IO、信号驱动IO和异步IO;前四种都是同步IO,在内核数据copy到用户空间时都是阻塞的。
阻塞IO和非阻塞IO的区别在于第一步,发起IO请求是否会被阻塞,如果会那就是传统的阻塞IO,如果不会那就是非阻塞IO。
同步IO和异步IO的区别就在于第二个步骤是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO;如果不阻塞,而是操作系统帮你做完IO操作再将结果返回给你,那么就是异步IO

IO复用技术

IO多路复用:I/O是指网络I/O,多路指多个TCP连接(即socket或者channel),复用指复用一个或几个线程意思说一个或一组线程处理多个TCP连接最大优势是减少系统开销小,不必创建过多的进程/线程,也不必维护这些进程/线程。
  IO多路复用使用两个系统调用(select/poll/epoll和recvfrom),blocking IO只调用了recvfrom;select/poll/epoll 核心是可以同时处理多个connection,而不是更快,所以连接数不高的话,性能不一定比多线程+阻塞IO好,多路复用模型中,每一个socket,设置为non-blocking,阻塞是被select这个函数block,而不是被socket阻塞的。

select机制
基本原理:
  客户端操作服务器时就会产生这三种文件描述符(简称fd):writefds(写)、readfds(读)、和exceptfds(异常)。select会阻塞住监视3类文件描述符,等有数据、可读、可写、出异常 或超时、就会返回;返回后通过遍历fdset整个数组来找到就绪的描述符fd,然后进行对应的IO操作。
优点:
  几乎在所有的平台上支持,跨平台支持性好
缺点:
  由于是采用轮询方式全盘扫描,会随着文件描述符FD数量增多而性能下降。
  每次调用 select(),需要把 fd 集合从用户态拷贝到内核态,并进行遍历(消息传递都是从内核到用户空间)
  默认单个进程打开的FD有限制是1024个,可修改宏定义,但是效率仍然慢。

poll机制:
  基本原理与select一致,也是轮询+遍历;唯一的区别就是poll没有最大文件描述符限制(使用链表的方式存储fd)。

epoll机制:
基本原理:
  没有fd个数限制,用户态拷贝到内核态只需要一次,使用时间通知机制来触发。通过epoll_ctl注册fd,一旦fd就绪就会通过callback回调机制来激活对应fd,进行相关的io操作。
epoll之所以高性能是得益于它的三个函数
  1)epoll_create()系统启动时,在Linux内核里面申请一个B+树结构文件系统,返回epoll对象,也是一个fd
  2)epoll_ctl() 每新建一个连接,都通过该函数操作epoll对象,在这个对象里面修改添加删除对应的链接fd, 绑定一个callback函数
  3)epoll_wait() 轮训所有的callback集合,并完成对应的IO操作
优点:   没fd这个限制,所支持的FD上限是操作系统的最大文件句柄数,1G内存大概支持10万个句柄   效率提高,使用回调通知而不是轮询的方式,不会随着FD数目的增加效率下降   内核和用户空间mmap同一块内存实现(mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间)