操作系统是三大系统类课程之一:
计算机组成原理 - 提供重要的抽象:指令集编译原理操作系统 - 提供的最重要的抽象:进程为何要学操作系统?
往大了说:操作系统是互联网世界的基础,其重要性不言而喻。往小了说:学好操作系统能帮助你更好的理解并发,以及很多奇奇怪怪的幺蛾子,比如我下面提到的问题8和问题10。这些问题有的是关乎我们日常使用电脑,有的是关乎开发时遇到的BUG,这些问题都与操作系统息息相关,想深入理解这些问题,好好学操作系统吧。
操作系统的概念来源:
将底层操作硬件设备的代码封装,提供统一的接口;即提供一个虚拟机 《CODE》一书的观点
操作系统发展的一个主线就是—追求效率,既然要追求效率,那么就得弄明白是什么导致的效率问题? 答案是:IO活动比计算活动慢得多。记住这句话,我们后面的很多机制都是因为IO活动比计算任务慢而引入的。
从上图可知,该操作系统同一时刻只能有一个任务执行,当有IO操作时: 即当一个任务在执行IO操作时,CPU是空闲的,即使有计算任务还未执行完毕,也只能等待IO操作完成才行。
基于上述问题,衍生出版本2
上图给出了一个内存抽象示意图,表示在内存中装入多个程序: A, B, C,当A需要执行IO时,可以将CPU切换至B工作,当B执行IO时,可以将CPU再次切换到C,上图给出了执行顺序图,这种方案显然比单道批处理效率高。
上述方案存在的问题: 会导致周转时间变长(从提交任务至获得输出的时间),如果程序A等待IO的时间极短,那么CPU仍然会被调度去执行程序B,然后C,调度一圈回来才能继续执行A,这样程序A空等时间大大增长。 所以衍生出版本3
版本2中:触发CPU调度的事件是:IO操作。这个方案有缺点根本原因是IO操作有的耗时短,有的耗时长。如果出现IO就去执行其他程序,并且轮一圈回来才继续执行,有可能会浪费很多时间,从而导致周转时间长。那么我们能不能换一个思路来改进上述方案?
试想能不能做到:A需要IO的时候就去执行B,当A的IO完成后立刻继续执行A。如果能做到的话,可以解决上述方案导致的周转时间长的缺陷。
版本2出发CPU调度的事件是某一个任务需要IO操作。
分时操作系统的CPU调度触发事件:给每个程序分配一个时间片,到时即触发CPU调度,比如给每个程序分20ms,20ms用完后就执行调度函数去执行其他程序。
设计者:John McCarthy,于1960年提出计算机分时概念,于1971年因对AI的贡献获图灵奖,目前的计算机都是使用这种方案。
思考为什么出现上述三个版本的衍化:一是为了提高运行效率,二是方便程序员管理,可以理解成提高开发效率。
其实计算机技术衍化的一个基本思路无非就是:运行效率和开发效率,当然从商业化角度思考还会考虑兼容性问题。
上面讨论了操作系统的3个版本的衍化,每一次衍化都会产生效率的提升,但是同时引入了额外的问题。
假设有两个程序A,B,这两个程序共用一个全局变量c,见下图: 上面汇编语句前面的数字表示运行顺序,分时系统可能会产生这种运行顺序。按照这个顺序运行时,我们得到的结果与预期不同。
这里读者可能会想到,这里出错的原因不仅仅在于变量c,还有一个原因是因为共享寄存器AX,如果不共享寄存器呢?这个问题留给读者去思考,可以先把答案给出,即使不共享寄存器也是会出错的。
接触过多线程的同学可能已经意识到了,对于这种情况需要对变量加锁,所以由于使用分时系统额外引入了锁机制。
下图的lock()只是一个示意,C语言库函数中并不存在该函数 锁机制:当在程序A中lock©后,再执行程序B,程序B会被阻塞,需要等待程序A将变量c解锁后才能使用。
那么我继续以同样的思路思考问题,引入锁机制后是否会带来其他问题?看下图 按照标号运行,运行1时程序A锁住变量p,运行2时程序B锁住变量c,运行3时程序A阻塞,即使调度到程序B仍然阻塞,这样程序A,B就卡住了,这就是死锁,对于这个问题后面会深入讨论。
这里其实很容易看出原因,如果把程序B两个lock语句以及unlock语句颠倒下顺序就能解决这个问题,这需要程序员去解决。但试想如果有10个,100个变量需要加锁呢?再假设程序A由小明编写,程序B由小红编写,他们都按照自己思路写,没有事先沟通好呢?这里是不是需要引入其他机制有效解决这个问题呢? 这里我们仅仅引入问题,后面深入探讨。
这里引出该问题的目的是想说明,在OS发展过程中:为了解决某些问题会引入其他机制,而因为该机制会出现其他问题,这样就需要不断引入新的机制,直到OS能稳定高效运行。
CPU状态:内核态与用户态
指令分类:特权指令与非特权指令
我们写的程序用到的指令都是非特权指令,特权指令只有操作系统可用。那么问题来了,如果我们需要使用特权指令需要的功能怎么办?操作系统给我们提供了调用接口-即系统调用系统调用是用户与内核交互的门户应用程序不能跨平台运行的原因:
不同操作系统提供的系统调用不同。解决方案也很容易想到:要么将系统调用统一起来(不太可能实现),要么做不同操作系统调用之间的映射, Linux下的Wine就是这样实现的兼容Windows程序。中断处理:
中断发生时,操作系统先处理,再转发给相应的用户程序操作系统如何实现程序之间的调度:定时器周期性产生时钟中断,产生时钟中断后跳到调度程序,从而实现调度。操作系统运行过程简述:
启动时:先启动内核模式,在内核模式下设置中断处理程序,创建用户进程,设置定时器周期性产生时钟中断。然后从内核态切换至用户态,运行用户程序。中断来临时:用户态切换至内核态,执行相应程序(中断处理程序),处理完毕后降级为用户态,执行权交给用户程序。并发与并行
并发指一定时间间隔内均运行并行指同一时刻同时运行交叉编译
在笔记本上编译安卓手机上的程序称为交叉编译。上面提到了应用程序在不同操作系统不兼容的问题,谈到了Wine,Wine是Linux系统上运行Windows程序的兼容层,Linux上跑的很多Windows程序都是利用这个技术,可以简单理解成其做了Windows与Linux系统调用的映射。
笔者曾经连续两个月(2018/6 – 2018/8)一直使用ubuntu16.04,中间没有开过Windows,试图体验使用Ubuntu办公 or 编程的感觉。这里分享给读者一些小小的经验,其实Windows下我们最依赖的社交软件是QQ(TIM)和WeChat,至于开发软件官方都提供了Linux支持。所以只要解决了QQ和微信,其他的都好说。
这里推荐两个GitHub项目:
Wine-QQ-TIM 我使用的是TIM,在Ubuntu16.04下可以使用,甚至连Ctrl+Alt+A截图功能都能使用,只不过文件系统做的不太统一,用起来可能有点小疑惑,崩溃率要比Windows上高 — 后来验证了一下,他们的下载地址好像失效了,当时没有备份下有点可惜。Electronic WeChat 使用Electron构建的一个可在Linux下运行的微信,支持上传文件下载文件,只不过体验不是很好,操作文件时有明显卡顿。上面两个项目已经2年多没人维护了,不过使用是没问题的,笔者也是靠着这两个东西在Ubuntu下硬抗了接近两个月。最终得出的结论是ubuntu的界面做的的确不怎么好,用户体验不好,这里建议读者将Linux当成Linux使用,而不要将Linux当成Windows使用,不然挫败感很强,而且体会不到Linux的强大。该系列博客目录地址 下一篇-进程概述