这是程序员cxuan的第七篇原创文章html
操做系统是运行在计算机上最重要的一种软件,它管理计算机的资源和进程以及全部的硬件和软件。它为计算机硬件和软件提供了一种中间层程序员
一般状况下,计算机上会运行着许多应用程序,它们都须要对内存和 CPU 进行交互,操做系统的目的就是为了保证这些访问和交互可以准确无误的进行。面试
操做系统是一种软件,它的主要目的有三种算法
操做系统一般预装在你购买计算机以前。大部分用户都会使用默认的操做系统,可是你也能够升级甚至更改操做系统。可是通常常见的操做系统只有三种:Windows、macOS 和 Linux。shell
4.一、单体系统编程
在大多数系统中,整个系统在内核态以单一程序的方式运行。整个操做系统是以程序集合来编写的,连接在一块造成一个大的二进制可执行程序,这种系统称为单体系统。浏览器
在单体系统中构造实际目标程序时,会首先编译全部单个过程(或包含这些过程的文件),而后使用系统连接器将它们所有绑定到一个可执行文件中服务器
在单体系统中,对于每一个系统调用都会有一个服务程序来保障和运行。须要一组实用程序来弥补服务程序须要的功能,例如从用户程序中获取数据。可将各类过程划分为一个三层模型网络
除了在计算机初启动时所装载的核心操做系统外,许多操做系统还支持额外的扩展。好比 I/O 设备驱动和文件系统。这些部件能够按需装载。在 UNIX 中把它们叫作 共享库(shared library),在 Windows 中则被称为 动态连接库(Dynamic Link Library,DLL)。他们的扩展名为 .dll,在 C:\Windows\system32 目录下存在 1000 多个 DLL 文件,因此不要轻易删除 C 盘文件,不然可能就炸了哦。多线程
4.二、分层系统
分层系统使用层来分隔不一样的功能单元。每一层只与该层的上层和下层通讯。每一层都使用下面的层来执行其功能。层之间的通讯经过预约义的固定接口通讯。
4.三、微内核
为了实现高可靠性,将操做系统划分红小的、层级之间可以更好定义的模块是颇有必要的,只有一个模块 --- 微内核 --- 运行在内核态,其他模块能够做为普通用户进程运行。因为把每一个设备驱动和文件系统分别做为普通用户进程,这些模块中的错误虽然会使这些模块崩溃,可是不会使整个系统死机。
MINIX 3 是微内核的表明做,它的具体结构以下
在内核的外部,系统的构造有三层,它们都在用户态下运行,最底层是设备驱动器。因为它们都在用户态下运行,因此不能物理的访问 I/O 端口空间,也不能直接发出 I/O 命令。相反,为了可以对 I/O 设备编程,驱动器构建一个结构,指明哪一个参数值写到哪一个 I/O 端口,并声称一个内核调用,这样就完成了一次调用过程。
4.四、客户-服务器模式
微内核思想的策略是把进程划分为两类:服务器,每一个服务器用来提供服务;客户端,使用这些服务。这个模式就是所谓的 客户-服务器模式。
客户-服务器模式会有两种载体,一种状况是一台计算机既是客户又是服务器,在这种方式下,操做系统会有某种优化;可是广泛状况下是客户端和服务器在不一样的机器上,它们经过局域网或广域网链接。
客户经过发送消息与服务器通讯,客户端并不须要知道这些消息是在本地机器上处理,仍是经过网络被送到远程机器上处理。对于客户端而言,这两种情形是同样的:都是发送请求并获得回应。
在操做系统中,进程是以页为单位加载到内存中的,按需分页是一种虚拟内存的管理方式。在使用请求分页的系统中,只有在尝试访问页面所在的磁盘而且该页面还没有在内存中时,也就发生了缺页异常,操做系统才会将磁盘页面复制到内存中。
随着处理器的不断增长,咱们的计算机系统由单机系统变为了多处理系统,多处理系统的吞吐量比较高,多处理系统拥有多个并行的处理器,这些处理器共享时钟、内存、总线、外围设备等。
多处理系统因为能够共享资源,所以能够开源节流,省钱。整个系统的可靠性也随之提升。
在计算机中,内核是一个计算机程序,它是操做系统的核心,能够控制操做系统中全部的内容。内核一般是在 boot loader 装载程序以前加载的第一个程序。
这里还须要了解一下什么是 boot loader。
boot loader 又被称为引导加载程序,它是一个程序,可以将计算机的操做系统放入内存中。在电源通电或者计算机重启时,BIOS 会执行一些初始测试,而后将控制权转移到引导加载程序所在的主引导记录(MBR) 。
实时操做系统对时间作出了严格的要求,实时操做系统分为两种:硬实时和软实时
硬实时操做系统规定某个动做必须在规定的时刻内完成或发生,好比汽车生产车间,焊接机器必须在某一时刻内完成焊接,焊接的太早或者太晚都会对汽车形成永久性伤害。
软实时操做系统虽然不但愿偶尔违反最终的时限要求,可是仍然能够接受。而且不会引发任何永久性伤害。好比数字音频、多媒体、手机都是属于软实时操做系统。
你能够简单理解硬实时和软实时的两个指标:是否在时刻内必须完成以及是否形成严重损害。
虚拟内存是一种内存分配方案,是一项能够用来辅助内存分配的机制。咱们知道,应用程序是按页装载进内存中的。但并非全部的页都会装载到内存中,计算机中的硬件和软件会将数据从 RAM 临时传输到磁盘中来弥补内存的不足。若是没有虚拟内存的话,一旦你将计算机内存填满后,计算机会对你说
呃,不,对不起,您没法再加载任何应用程序,请关闭另外一个应用程序以加载新的应用程序。对于虚拟内存,计算机能够执行操做是查看内存中最近未使用过的区域,而后将其复制到硬盘上。虚拟内存经过复制技术实现了 妹子,你快来看哥哥能装这么多程序 的资本。复制是自动进行的,你没法感知到它的存在。
进程就是正在执行程序的实例,好比说 Web 程序就是一个进程,shell 也是一个进程,文章编辑器 typora 也是一个进程。
操做系统负责管理全部正在运行的进程,操做系统会为每一个进程分配特定的时间来占用 CPU,操做系统还会为每一个进程分配特定的资源。
操做系统为了跟踪每一个进程的活动状态,维护了一个进程表。在进程表的内部,列出了每一个进程的状态以及每一个进程使用的资源等。
http://courses.cs.vt.edu/csonline/OS/Lessons/Processes/index.html ( http://courses.cs.vt.edu/csonline/OS/Lessons/Processes/index.html ) 这个网站上面有一个关于进程状态轮转的动画,作的真是太好了。
这又是一道老生常谈的问题了,从操做系统的角度来回答一下吧。
咱们上面说到进程是正在运行的程序的实例,而线程其实就是进程中的单条流向,由于线程具备进程中的某些属性,因此线程又被称为轻量级的进程。浏览器若是是一个进程的话,那么浏览器下面的每一个 tab 页能够看做是一个个的线程。
下面是线程和进程持有资源的区别
线程不像进程那样具备很强的独立性,线程之间会共享数据
建立线程的开销要比进程小不少,由于建立线程仅仅须要堆栈指针和程序计数器就能够了,而建立进程须要操做系统分配新的地址空间,数据资源等,这个开销比较大。
十二、使用多线程的好处是什么
多线程是程序员不得不知的基本素养之一,因此,下面咱们给出一些多线程编程的好处
可以提升对用户的响应顺序
在流程中的资源共享
比较经济适用
可以对多线程架构有深刻的理解
RR(round-robin) 调度算法主要针对分时系统,RR 的调度算法会把时间片以相同的部分并循环的分配给每一个进程,RR 调度算法没有优先级的概念。这种算法的实现比较简单,并且每一个线程都会占有时间片,并不存在线程饥饿的问题。
死锁的出现须要同时知足下面四个条件
- 互斥(Mutual Exclusion):一次只能有一个进程使用资源。若是另外一个进程请求该资源,则必须延迟请求进程,直到释放该资源为止。
- 保持并等待(Hold and Wait):必须存在一个进程,该进程至少持有一个资源,而且正在等待获取其余进程当前所持有的资源。
- 无抢占(No Preemption):资源不能被抢占,也就是说,在进程完成其任务以后,只能由拥有它的进程自动释放资源。
- 循环等待(Circular Wait) :必须存在一组 {p0,p1,..... pn} 的等待进程,使 p0 等待 p1 持有的资源,p1 等待由 p2 持有的资源, pn-1 正在等待由 pn 持有的资源,而 pn 正在等待由 p0 持有的资源。
RAID 称为 磁盘冗余阵列,简称 磁盘阵列。利用虚拟化技术把多个硬盘结合在一块儿,成为一个或多个磁盘阵列组,目的是提高性能或数据冗余。
RAID 有不一样的级别
- RAID 0 - 无容错的条带化磁盘阵列
- RAID 1 - 镜像和双工
- RAID 2 - 内存式纠错码
- RAID 3 - 比特交错奇偶校验
- RAID 4 - 块交错奇偶校验
- RAID 5 - 块交错分布式奇偶校验
- RAID 6 - P + Q 冗余
DMA 的中文名称是直接内存访问,它意味着 CPU 授予 I/O 模块权限在不涉及 CPU 的状况下读取或写入内存。也就是 DMA 能够不须要 CPU 的参与。这个过程由称为 DMA 控制器(DMAC)的芯片管理。因为 DMA 设备能够直接在内存之间传输数据,而不是使用 CPU 做为中介,所以能够缓解总线上的拥塞。DMA 经过容许 CPU 执行任务,同时 DMA 系统经过系统和内存总线传输数据来提升系统并发性。
对不起,我忍不住想偷笑
说直白点,为何单线程可以处理的却要用多线程来处理?固然是为了提升程序的装逼并行能力了。多线程在某些状况下可以使你程序运行的更快,这也是为何多核 CPU 会出现,可是多核 CPU 的出现会致使数据的一致性问题,不过这些问题程序员就能解决。另外一个角度来讲,多线程编程可以提升程序员的编程能力和编程思惟。同时也能提升程序员的管理能力,你若是把每条线程流看成罗老师时间管理的女主同样,可以及时协调好全部 P 友的关系,那你也是超神程序员了,因此,是谁说程序员不会作管理的?Doug Lea 大佬牛逼!!!
ps:Doug Lea 大佬开发的 JUC 工具包,此处不加狗头。
在计算机中,设备驱动程序是一种计算机程序,它可以控制或者操做链接到计算机的特定设备。驱动程序提供了与硬件进行交互的软件接口,使操做系统和其余计算机程序可以访问特定设备,不用须要了解其硬件的具体构造。
19.一、通讯概念
进程间的通讯方式比较多,首先你须要理解下面这几个概念
竞态条件:即两个或多个线程同时对一共享数据进行修改,从而影响程序运行的正确性时,这种就被称为竞态条件(race condition)。
临界区:不只共享资源会形成竞态条件,事实上共享文件、共享内存也会形成竞态条件、那么该如何避免呢?或许一句话能够归纳说明:禁止一个或多个进程在同一时刻对共享资源(包括共享内存、共享文件等)进行读写。换句话说,咱们须要一种 互斥(mutual exclusion) 条件,这也就是说,若是一个进程在某种方式下使用共享变量和文件的话,除该进程以外的其余进程就禁止作这种事(访问统一资源)。
一个好的解决方案,应该包含下面四种条件
- 任什么时候候两个进程不能同时处于临界区
- 不该对 CPU 的速度和数量作任何假设
- 位于临界区外的进程不得阻塞其余进程
- 不能使任何进程无限等待进入临界区
忙等互斥:当一个进程在对资源进行修改时,其余进程必须进行等待,进程之间要具备互斥性,咱们讨论的解决方案其实都是基于忙等互斥提出的。
19.二、解决方案
进程间的通讯用专业一点的术语来表示就是 Inter Process Communication,IPC,它主要有下面几种通讯方式
- 消息传递:消息传递是进程间实现通讯和同步等待的机制,使用消息传递,进程间的交流不须要共享变量,直接就能够进行通讯;消息传递分为发送方和接收方
- 先进先出队列:先进先出队列指的是两个不相关联进程间的通讯,两个进程之间能够彼此相互进程通讯,这是一种全双工通讯方式
- 管道:管道用于两个相关进程之间的通讯,这是一种半双工的通讯方式,若是须要全双工,须要另一个管道。
- 直接通讯:在这种进程通讯的方式中,进程与进程之间只存在一条连接,进程间要明确通讯双方的命名。
- 间接通讯:间接通讯是通讯双方不会直接创建链接,而是找到一个中介者,这个中介者多是个对象等等,进程能够在其中放置消息,而且能够从中删除消息,以此达到进程间通讯的目的。
- 消息队列:消息队列是内核中存储消息的链表,它由消息队列标识符进行标识,这种方式可以在不一样的进程之间提供全双工的通讯链接。
- 共享内存:共享内存是使用全部进程之间的内存来创建链接,这种类型须要同步进程访问来相互保护。
cat chapter1 chapter2 chapter3 | grep tree
第一个进程是 cat,将三个文件级联并输出。第二个进程是 grep,它从输入中选择具备包含关键字 tree 的内容,根据这两个进程的相对速度(这取决于两个程序的相对复杂度和各自所分配到的 CPU 时间片),可能会发生下面这种状况,grep 准备就绪开始运行,可是输入进程尚未完成,因而必须阻塞 grep 进程,直到输入完毕。
当一个进程开始运行时,它可能会经历下面这几种状态
图中会涉及三种状态
- 运行态,运行态指的就是进程实际占用 CPU 时间片运行时
- 就绪态,就绪态指的是可运行,但由于其余进程正在运行而处于就绪状态
- 阻塞态,除非某种外部事件发生,不然进程不能运行
逻辑上来讲,运行态和就绪态是很类似的。这两种状况下都表示进程可运行,可是第二种状况没有得到 CPU 时间分片。第三种状态与前两种状态不一样的缘由是这个进程不能运行,CPU 空闲时也不能运行。
三种状态会涉及四种状态间的切换,在操做系统发现进程不能继续执行时会发生状态 1的轮转,在某些系统中进程执行系统调用,例如 pause,来获取一个阻塞的状态。在其余系统中包括 UNIX,当进程从管道或特殊文件(例如终端)中读取没有可用的输入时,该进程会被自动终止。
转换 2 和转换 3 都是由进程调度程序(操做系统的一部分)引发的,进程自己不知道调度程序的存在。转换 2 的出现说明进程调度器认定当前进程已经运行了足够长的时间,是时候让其余进程运行 CPU 时间片了。当全部其余进程都运行事后,这时候该是让第一个进程从新得到 CPU 时间片的时候了,就会发生转换 3。
程序调度指的是,决定哪一个进程优先被运行和运行多久,这是很重要的一点。已经设计出许多算法来尝试平衡系统总体效率与各个流程之间的竞争需求。
当进程等待的一个外部事件发生时(如从外部输入一些数据后),则发生转换 4。若是此时没有其余进程在运行,则马上触发转换 3,该进程便开始运行,不然该进程会处于就绪阶段,等待 CPU 空闲后再轮到它运行。
调度算法分为三大类:批处理中的调度、交互系统中的调度、实时系统中的调度
21.一、批处理中的调度
先来先服务
很像是先到先得。。。可能最简单的非抢占式调度算法的设计就是 先来先服务(first-come,first-serverd)。使用此算法,将按照请求顺序为进程分配 CPU。最基本的,会有一个就绪进程的等待队列。当第一个任务从外部进入系统时,将会当即启动并容许运行任意长的时间。它不会由于运行时间太长而中断。当其余做业进入时,它们排到就绪队列尾部。当正在运行的进程阻塞,处于等待队列的第一个进程就开始运行。当一个阻塞的进程从新处于就绪态时,它会像一个新到达的任务,会排在队列的末尾,即排在全部进程最后。
这个算法的强大之处在于易于理解和编程,在这个算法中,一个单链表记录了全部就绪进程。要选取一个进程运行,只要从该队列的头部移走一个进程便可;要添加一个新的做业或者阻塞一个进程,只要把这个做业或进程附加在队列的末尾便可。这是很简单的一种实现。
不过,先来先服务也是有缺点的,那就是没有优先级的关系,试想一下,若是有 100 个 I/O 进程正在排队,第 101 个是一个 CPU 密集型进程,那岂不是须要等 100 个 I/O 进程运行完毕才会等到一个 CPU 密集型进程运行,这在实际状况下根本不可能,因此须要优先级或者抢占式进程的出现来优先选择重要的进程运行。
最短做业优先
批处理中,第二种调度算法是 最短做业优先(Shortest Job First),咱们假设运行时间已知。例如,一家保险公司,由于天天要作相似的工做,因此人们能够至关精确地预测处理 1000 个索赔的一批做业须要多长时间。当输入队列中有若干个同等重要的做业被启动时,调度程序应使用最短优先做业算法
如上图 a 所示,这里有 4 个做业 A、B、C、D ,运行时间分别为 八、四、四、4 分钟。若按图中的次序运行,则 A 的周转时间为 8 分钟,B 为 12 分钟,C 为 16 分钟,D 为 20 分钟,平均时间内为 14 分钟。
如今考虑使用最短做业优先算法运行 4 个做业,如上图 b 所示,目前的周转时间分别为 四、八、十二、20,平均为 11 分钟,能够证实最短做业优先是最优的。考虑有 4 个做业的状况,其运行时间分别为 a、b、c、d。第一个做业在时间 a 结束,第二个在时间 a + b 结束,以此类推。平均周转时间为 (4a + 3b + 2c + d) / 4 。显然 a 对平均值的影响最大,因此 a 应该是最短优先做业,其次是 b,而后是 c ,最后是 d 它就只能影响本身的周转时间了。
须要注意的是,在全部的进程均可以运行的状况下,最短做业优先的算法才是最优的。
最短剩余时间优先
最短做业优先的抢占式版本被称做为 最短剩余时间优先(Shortest Remaining Time Next) 算法。使用这个算法,调度程序老是选择剩余运行时间最短的那个进程运行。当一个新做业到达时,其整个时间同当前进程的剩余时间作比较。若是新的进程比当前运行进程须要更少的时间,当前进程就被挂起,而运行新的进程。这种方式可以使短时间做业得到良好的服务。
21.二、交互式系统中的调度
交互式系统中在我的计算机、服务器和其余系统中都是很经常使用的,因此有必要来探讨一下交互式调度
轮循调度
一种最古老、最简单、最公平而且最普遍使用的算法就是 轮循算法(round-robin)。每一个进程都会被分配一个时间段,称为时间片(quantum),在这个时间片内容许进程运行。若是时间片结束时进程还在运行的话,则抢占一个 CPU 并将其分配给另外一个进程。若是进程在时间片结束前阻塞或结束,则 CPU 当即进行切换。轮循算法比较容易实现。调度程序所作的就是维护一个可运行进程的列表,就像下图中的 a,当一个进程用完时间片后就被移到队列的末尾,就像下图的 b。
优先级调度
事实状况是否是全部的进程都是优先级相等的。例如,在一所大学中的等级制度,首先是院长,而后是教授、秘书、后勤人员,最后是学生。这种将外部状况考虑在内就实现了优先级调度(priority scheduling)
它的基本思想很明确,每一个进程都被赋予一个优先级,优先级高的进程优先运行。
可是也不意味着高优先级的进程可以永远一直运行下去,调度程序会在每一个时钟中断期间下降当前运行进程的优先级。若是此操做致使其优先级下降到下一个最高进程的优先级如下,则会发生进程切换。或者,能够为每一个进程分配容许运行的最大时间间隔。当时间间隔用完后,下一个高优先级的进程会获得运行的机会。
最短进程优先
对于批处理系统而言,因为最短做业优先经常伴随着最短响应时间,一种方式是根据进程过去的行为进行推测,并执行估计运行时间最短的那一个。假设每一个终端上每条命令的预估运行时间为 T0,如今假设测量到其下一次运行时间为 T1,能够用两个值的加权来改进估计时间,即aT0+ (1- 1)T1。经过选择 a 的值,能够决定是尽快忘掉老的运行时间,仍是在一段长时间内始终记住它们。当 a = 1/2 时,能够获得下面这个序列
能够看到,在三轮事后,T0 在新的估计值中所占比重降低至 1/8。
有时把这种经过当前测量值和先前估计值进行加权平均从而获得下一个估计值的技术称做 老化(aging)。这种方法会使用不少预测值基于当前值的状况。
彩票调度
有一种既能够给出预测结果而又有一种比较简单的实现方式的算法,就是 彩票调度(lottery scheduling)算法。他的基本思想为进程提供各类系统资源的彩票。当作出一个调度决策的时候,就随机抽出一张彩票,拥有彩票的进程将得到资源。好比在 CPU 进行调度时,系统能够每秒持有 50 次抽奖,每一个中奖进程会得到额外运行时间的奖励。
能够把彩票理解为 buff,这个 buff 有 15% 的概率能让你产生 速度之靴 的效果。
公平分享调度
若是用户 1 启动了 9 个进程,而用户 2 启动了一个进程,使用轮转或相同优先级调度算法,那么用户 1 将获得 90 % 的 CPU 时间,而用户 2 将之获得 10 % 的 CPU 时间。
为了阻止这种状况的出现,一些系统在调度前会把进程的拥有者考虑在内。在这种模型下,每一个用户都会分配一些 CPU 时间,而调度程序会选择进程并强制执行。所以若是两个用户每一个都会有 50% 的 CPU 时间片保证,那么不管一个用户有多少个进程,都将得到相同的 CPU 份额。
2二、页面置换算法都有哪些
算法 注释 最优算法 不可实现,但能够用做基准 NRU(最近未使用) 算法 和 LRU 算法很类似 FIFO(先进先出) 算法 有可能会抛弃重要的页面 第二次机会算法 比 FIFO 有较大的改善 时钟算法 实际使用 LRU(最近最少)算法 比较优秀,可是很难实现 NFU(最不常用)算法 和 LRU 很相似 老化算法 近似 LRU 的高效算法 工做集算法 实施起来开销很大 工做集时钟算法 比较有效的算法
- 最优算法在当前页面中置换最后要访问的页面。不幸的是,没有办法来断定哪一个页面是最后一个要访问的,所以实际上该算法不能使用。然而,它能够做为衡量其余算法的标准。
- NRU 算法根据 R 位和 M 位的状态将页面分为四类。从编号最小的类别中随机选择一个页面。NRU 算法易于实现,可是性能不是很好。存在更好的算法。
- FIFO 会跟踪页面加载进入内存中的顺序,并把页面放入一个链表中。有可能删除存在时间最长可是还在使用的页面,所以这个算法也不是一个很好的选择。
- 第二次机会算法是对 FIFO 的一个修改,它会在删除页面以前检查这个页面是否仍在使用。若是页面正在使用,就会进行保留。这个改进大大提升了性能。
- 时钟 算法是第二次机会算法的另一种实现形式,时钟算法和第二次算法的性能差很少,可是会花费更少的时间来执行算法。
- LRU 算法是一个很是优秀的算法,可是没有特殊的硬件(TLB)很难实现。若是没有硬件,就不能使用 LRU 算法。
- NFU 算法是一种近似于 LRU 的算法,它的性能不是很是好。
- 老化 算法是一种更接近 LRU 算法的实现,而且能够更好的实现,所以是一个很好的选择
- 最后两种算法都使用了工做集算法。工做集算法提供了合理的性能开销,可是它的实现比较复杂。WSClock 是另一种变体,它不只可以提供良好的性能,并且能够高效地实现。
最好的算法是老化算法和 WSClock 算法。他们分别是基于 LRU 和工做集算法。他们都具备良好的性能而且可以被有效的实现。还存在其余一些好的算法,但实际上这两个多是最重要的。
会有下面几个因素决定调度程序的好坏
CPU 使用率:
CPU 正在执行任务(即不处于空闲状态)的时间百分比。等待时间
这是进程轮流执行的时间,也就是进程切换的时间吞吐量
单位时间内完成进程的数量响应时间
这是从提交流程到得到有用输出所通过的时间。- 周转时间
从提交流程到完成流程所通过的时间。
僵尸进程是已完成且处于终止状态,但在进程表中却仍然存在的进程。僵尸进程一般发生在父子关系的进程中,因为父进程仍须要读取其子进程的退出状态所形成的。
往期精选
这是对cxuan熬夜肝文章最好的奖励。
cxuan我写的还行么?喜欢做者