操作系统
# 前言
敲重点! 操作系统 最核心的概念就是 进程!
进程是啥?别觉得很深奥,它啥也不是,就是一个方便沟通,发明的名词而已..
指的是一个程序的运行过程,具体来说是 操作系统控制硬件(cpu、硬盘、内存等)来运行程序的过程 ..
简单来说, 我们经常提到的<进程>说的就是<内存中的程序>,即程序从硬盘加载到内存了..
# 为什么要有OS?
程序员无法把所有的硬件操作细节都了解到, 管理这些硬件并且加以优化使用是非常繁琐的工作.
这个繁琐的工作应该由操作系统来完成,这样的话,程序员就只需要专注于自己应用软件的编写, 编写好的应用软件会直接调用操作系统提供的功能来间接使用硬件...
# 什么是OS?
操作系统是一个协调、管理和控制计算机底层的硬件资源和上层的软件资源的控制程序!
Q: 操作系统是运行于内核态的?
A: 单纯的说操作系统是运行于内核态是不准确的..
操作系统位于计算机硬件与应用软件之间, 本质也是一个软件
操作系统由 操作系统的内核 (运行于内核态,管理硬件资源)以及 系统调用 (运行于用户态,为应用程序员写的应用程序提供系统调用接口)两部分组成..
Ps: 系统调用接口,即提供给应用程序调用硬件资源的接口..是一种对硬件资源的抽象.
比如操作系统提供了文件这个抽象概念, 对文件的操作就是对磁盘的操作, 有了文件我们无需再去考虑关于磁盘的读写控制.
# 操作系统发展史
操作系统跟计算机硬件是同步发展的.. 操作系统是伴随着硬件的升级一点点升级的.
# 第一代
第一代计算机(1940~1955): 真空管和穿孔卡片
所有的程序设计都是直接操控硬件! 没有操作系统的概念.
程序员预约后,在预约的时间段只能程序员一个人用,独享计算机资源..
一旦程序出bug,排查时间段计算机资源是浪费的 并且同一时刻只有一个程序在内存中被cpu调用执行..
# 第二代
第二代计算机(1955~1965): 晶体管和批处理系统
真空管很容易烧 ,改进成了 晶体管; 当时的计算机很昂贵,为了提高计算机资源利用率,使用了 批处理系统..
共三台计算机,二台1401侧重于IO,一台7094侧重于运算; 一堆卡片 通过1401读入磁带机,经过系统磁带处理后, 输入磁带给7094,7094批处理运算后输出磁带给另一台1401进行打印..
# 何为批处理系统?
批处理系统 -- 单用户单任务
简单举个栗子,一次性输入给计算机10个程序,计算机 依次 将其放入内存中运行,再一起输出..
在这一过程中,跟第一代同样的,计算机一次只能把一个/道程序读入内存,运行完毕后,再执行下一个程序,没有并发,称之为 <串行>. 你细品,是有进程那味道在里面的(´▽`)
可能你会想,某一道程序出错了,不就阻塞在那了吗?程序有异常处理啊,打印出错信息.继续运行下一个程序.
优: 充分利用了计算机资源
劣: 1> 整个过程是需要人参与的,将磁带搬来搬去;
2> 程序运行是仍然是串行的,会攒一大波再一起输出,让程序员明显感觉到等待.. 不能即时调试程序..
本质上是单任务单用户,没有并发,是 串行
# 第三代
第三代计算机(1965~1980): 集成电路芯片和多道程序设计
提一嘴: IBM公司发明 system/360 系列的计算机 集IO与运算于一身. 此乃现在服务器的 鼻祖..
第二代计算机的第一个缺点通过SPOOLING技术解决了;第二个缺点通过多道技术实现并发来解决..
Ps: 若有多个任务, 串行是一个运行完毕后再运行下一个;并发的话看起来是同时运行的..
并发: 多个进程看起来是同时运行的. 把时间分成若干段,使多个进程快速交替的执行
并行: 多个进程真正意义上的同时运行,只有多个cpu(不管是单核还是多核的)才能实现多个进程并行.
Ps 线程的并发并行暂且不谈,后面再说..
# 多道技术产生背景
多道技术 -- 并发
后续的操作系统都采用了多道技术..
Ps: 我们往往图省事,说cpu在多个任务之间切换;实则操作系统控制cpu去切换的..
若CPU有四个核,那么每个核都在任务(往往指的是线程)之间切换.
cpu在执行一个任务的过程中,若需要操作硬盘,则发送操作硬盘的指令.
指令一旦发出,硬盘上的机械手臂滑动读取数据到内存中.
这一段时间,cpu需要等待,时间看似很短很短,但对于cpu来说已经很长很长,长到可以让cpu做很多其他的任务.
如果我们让cpu在这段时间内切换到去做其他的任务,这样cpu不就充分利用了吗? 最大限度的利用cpu资源.
2
3
4
# 空间上的复用
多道技术 -- 空间上的复用: 多道程序在运行前必须先加载到内存中.(也就变成了多个进程)
Ps: 多个进程的内存空间是相互隔离的,并且是物理隔离!(即硬件层面的隔离)
安全性 -- 多个进程之间的数据不互通; 稳定性 -- 退出程序只会释放掉自个儿的内存空间.
正因为实现了进程内存之间的物理隔离,分时系统才能流行起来..
Q:如何隔离的??
A:操作系统主要有五大功能:作业管理、进程管理、存储管理、设备管理和文件管理..
操作系统调用硬件资源给上层的软件使用..而硬件资源中的cpu是这些硬件资源的老大..cpu它承担了所有的计算任务
提一嘴,作业、程序、进程之间的关系:
参考资料: https://blog.csdn.net/hguisu/article/details/1910803
作业 -- 用户在一次解决或是一个事务处理过程中要求计算机系统所做的工作的集合
进程 -- 一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,
是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体.
1> 进程与作业是一一对应的.(❌)
执行一个作业可能会运行多个不同的进程,且必须至少由一个进程组成,反之不成立;
2> 进程与程序是一一对应的.(❌)
一个程序可以启动多个进程;一个进程也可以有序地执行若干程序
3> 程序是静态的,而进程是动态的..
接下来需要了解几个概念:逻辑(相对)地址、线性(虚拟)地址、物理(绝对)地址、分段机制、分页机制、段页式复合
1> cpu经过MMU内存管理单元可以转换得到外地址总线的位数,此位数决定了物理地址空间的大小..
2> CPU使用物理地址索引计算机的所有硬件资源
3> 一个硬件平台只有一个物理地址空间,而每个程序都认为自己独享整个平台的资源..
所以有了线性地址, 线性地址空间的大小往往于cpu的位数一致,32位的cpu,那么线性空间的大小就位2^32=4GB.
(物理地址空间的大小与线性空间的大小没有必然联系)
4> 线性地址可以映射到某一部分物理地址空间或整个物理地址空间..
尽管一个硬件平台只有一个物理地址空间 但一个硬件平台可以有多个线性地址空间..
5> x86架构的cpu内存管理机制分为两个部分:分段机制和分页机制.
分段和分页机制实现了程序之间的隔离..
分页机制实现了比分段机制更粒度化的管理..
分页机制还可以实现虚拟内存..
6> 分段机制启用,分页机制未启用: 逻辑 --> 线性 == 物理地址
分段分页机制同时启用: 逻辑 --> 线性 --> 物理地址
(具体的转换过程,就不是一丁半点能阐述清楚的啦,知道这个大体方向就行啦,具体过程暂且不用了解.略过.)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 时间上的复用
多道技术 -- 时间上的复用: 多个任务复用cpu的时间片,通俗来讲,就是cpu在多个程序之间来回快速切换.
不难看出,空间上的复用是在为时间上的复用做铺垫,为了让cpu切换的快一些..
注意哦! cpu是硬件,来回切换是受操作系统这一软件控制的.. 多道技术是应用在操作系统上的!
有三个任务A B C.先依次加载到内存中.
它们需要cpu运算的时间都是1s,运算完后产生的数据需要放到硬盘里,硬盘IO时间都是9s..
Q: 使用多道技术,完成这3个任务需要多长时间?
A: 1+1+1+9 = 12s.
想通关键的一点在于,在做任务C的IO时,任务A和B的IO也在做,当任务C的IO做完时,AB的IO早就做完了.
而cpu在三个任务之间切换的时间忽略不计..
先补充一个知识点,在实际情况下,哪怕任务A只有运算没有IO,若此任务A占用cpu的时间过长(你问多长算长,OS内部代码的事情了,我们不必care..),也会被操作系统一脚踹开,腾出cpu给其它任务用..
Q: 若任务ABC都只有运算时间10s,都没有IO..这种情况下,并发真的比串行效率高吗?
A: 串行30s,并行是大于30s的,因为还要考虑cpu切换进程的时间..
即cpu在没有遇到IO的情况下切换,不会切换效率,反而会降低效率..
但真实情况下,还是得切,因为得实现并发,就不能让cpu被捆绑的时间过长.
2
3
4
5
6
7
8
9
10
11
12
13
综上, 什么时候切换?
情况一: 当一个任务遇到IO,肯定要切换 -- 效率提升
情况二: 一个任务没有遇到IO但是占用cpu时间过长,也要切换 -- 降低效率
# 分时操作系统CTTS
核心就是应用 多道技术 来实现多个任务/进程的 并发 运行. -- 多用户多任务
▲ 仅从操作系统角度看:
Linux/Unix是一个多用户、多任务的操作系统
windows是一个单用户多任务操作系统
多用户不是说可以创建多个用户,而是指一次可以登录多个用户
多任务指的是可以并发执行多个进程
▲ 从网络技术的角度:
连机终端在没有互联网的情况下是有意义的,多个人可以用不同的连机终端连到一台机器/服务器上使用
而有了互联网之后,多个人可通过网络访问服务器,这个时候多用户or单用户的概念就不再那么重要
提一嘴:windows剪切板实际上是所有进程的共享内存.. linux里面的管道也是一种共享内存.
2
3
4
5
6
7
8
9
10
11
12
分时操作系统 = 多个联机终端 + 多道技术.
10个客户端/10个程序猿 通过联机设备(没有网络哦) 加载自己的程序到计算机内存.(10个进程)
计算机操作系统使用多道技术让计算机的这一颗cpu在这10个进程之间来回切换进行运算..
使得这10个程序员以为自己独享了计算机资源... (当时没有多核多cpu)
Ps: 当时的分时操作系统只能支持10几个联机终端.
<聊一点点稗官野史>
CTTS -- MULTICS -- unix -- minix -- linux -- linux发行版:redhat、centos
MIT,贝尔实验室和通用电气在CTTS成功研制后决定开发能够同时支持上百终端的MULTICS
但其设计者着眼于建造满足波士顿地区所有用户计算需求的一台机器, 一开始就追求完美,最后项目流产了.
后来一位参加过MULTICS研制的贝尔实验室计算机科学家"Ken Thompson"!!
它开发了一个简易的,单用户版本的MULTICS,最早只支持2个联机终端 --- 这就是后来大名鼎鼎的"UNIX系统"的前身!!!
1970年 -- UNIX诞生 称之为UNIX元年.UNIX系统最开始是使用汇编语言B语言写的!!
1973年 Ken Thompson和c语言之父丹尼斯里奇一起用c语言重构了UNIX..
Ps: 如今开发操作系统的语言也是C语言..(c语言是在高级语言中是最接近硬件的语言,效率最高)
1974年 UNIX第一次公之于众,共享了源代码,大家集思广益,得到迅速的发展
1979年 在UNIX基础上研究TCP/IP协议,极大促进了UNIX的发展
(敲黑板!这使得Linux在网络服务领域性能非常强大 linux系统的老祖宗是unix)
(也因为网络的出现,使得多用户的用处不大,计算机能通过网络支持更多用户..)
1984年 因为UNIX的商业化,Andrew S.anenbaum开发了一个Minix的教学操作系统.
(对外称未参照UNIX 骗小孩.. 但源代码是开源了的)
1985年 Richard Stallman对UNIX的商业化感到愤怒.
发起了一个名为GNU的开源计划,其中定制的GPL条款直接奠定了如今的开源基调.
1991年 芬兰大学生Linus Torvalds从Minix上获取了些灵感,开发并开源了linux系统.
Linux操作系统最高有7个终端就是致敬unix系统(unix系统最高也是7个)
不得不提,Linux系统有个重要的概念 -- 一切皆文件.
因为开源,后来有了linux各种各样的发行版(把linux源码拿来改一改加点自己的东西),比如红帽、ubuntu、麒麟等.
因为红帽收费大家对它不满,又拿来改吧改吧(当然红帽也是遵循开源协议..)
几乎把红帽全盘扒拉下来,把里面带有明显特征的比如名字命名redhat改了,logo改了.. -- CentOS
再说过个小故事
linux是开源的,一开始linux社区的程序员会将更新的代码托管到第三方平台上..
后来社区的人开始破解这个平台的协议,遭到了平台的警告..
linux社区的大佬们受这气?直接开发了一个名为git的软件来更好的管理linux的内核开发..
(知道为啥叫git吗?git的英文翻译叫做蠢货.. xswl)
Git是目前最主流的分布式版本控制系统(在本地)
Github是最主流的代码托管平台(号称全球最大的同性交友网站 Hhhh),可理解成一个存放和管理代码的平台.
Git ≠ Github. Git是抓手,Github是平台.没有必然的联系.
乔布斯跟比尔盖茨关于图形界面操作系统的故事..略.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 进程与线程
# 概念
<进程>是 操作系统分配资源 的最小单位; <线程>是程序执行/ cpu调度 的最小单位
在这篇笔记的开始,就事先提及了进程的概念. 进程可以指代加载到内存中的一个个的程序;也可以说是操作系统控制硬件来运行程序的一个过程..
这一过程用一个公式表示: 进程 = 资源申请(开辟内存空间) + 程序执行(运行代码)
这里不得不着重单独提一提程序与进程的区别: 程序指的是一个静态的指令序列(说白了,就是代码),而进程是一个容器,其中包含了一个程序的特定实例所用到的所有资源...
那么线程是什么呢?线程是从进程中抽象出的一个更细的单位..(线程包含于进程)
官方解释:
线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位
跟进程这一名词一样(黑话),为了方便沟通发明了线程. 将线程作为程序执行/ cpu调度 的最小单位, 因为cpu只会负责上方进程公式里运算部分(运行代码), 资源申请的部分操作系统会负责...
概括来讲:
<进程是资源单位> -- 一个程序在运行过程中使用的数据都与自己的进程有关
<线程是执行单位,cpu执行的线程> -- 进程内代码的运行过程
在上文多道技术那,我们提及到了与cpu调度相关的 时间片 概念.. cpu会在多个进程之间来回快速切换,现在引入了线程,那么我们可以更准确点来说,看得更细一点,cpu的时间片是作用于线程的..
起了一个qq进程 --- 开辟一块内存空间,将数据从硬盘读到内存,开始运行代码(开始运行qq的多个线程)
起了一个qq线程 --- 通常一个进程有多个线程,so此流水线只是指一部分程序代码的运行
[注意] 很多文献中,不会具体提及是进程还是线程,会说是task任务,那么就需要结合语境分析. 若与cpu调度相关,此处的任务大概率是说线程;若与操作系统分配资源与关,此处的任务大概率是指进程..
若计算机操作系统起了2个进程(通常一个软件就起一个进程),每个进程都有3个线程,则cpu并发了2x3=6个任务(站在线程的角度 即此处的任务是指线程)
1> 计算机的核心是CPU,它承担了所有的计算任务. 它就像一座工厂,时刻在运行.
2> 假定工厂的电力有限,一次只能供给一个车间使用. 也就是说,一个车间开工的时候,其他车间都必须停工.
背后的含义就是, 单个CPU一次只能运行一个任务.
3> 进程就好比工厂的车间,它代表CPU所能处理的单个任务.任一时刻,CPU总是运行一个进程,其他进程处于非运行状态.
4> 一个车间(进程)里,可以有很多工人(线程),即一个进程可以包括多个线程.. 它们(多个线程)协同完成一个任务(进程).
5> 每个工人有自己的任务,也有自己的事情做.(此处的任务站在线程的角度说的)
6> 车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的.
这象征一个进程的内存空间是进程里的每个线程所共享的.
7> 可是,每间房间的大小不同,有些房间最多只能容纳一个人.
比如厕所,里面有人的时候,其他人就不能进去了.
这代表一个线程使用某些共享内存时,其他线程必须等它结束才能使用这一块内存。
8> 一个防止他人进入的简单方法,就是门口加一把锁.先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去.
这就叫“互斥锁”(Mutual exclusion,缩写 Mutex)防止多个线程同时读写某一块内存区域.
9> 还有些房间,可以同时容纳n个人,比如厨房. 也就是说,如果人数大于n,多出来的人只能在外面等着.
这好比某些内存区域,只能供给固定数目的线程使用.
10> 这时的解决方法就是在门口挂n把钥匙. 进去的人就取一把钥匙,出来时再把钥匙挂回原处.
后到的人发现钥匙架空了,就知道必须在门口排队等着了.
这种做法叫做“信号量”(Semaphore),用来保证多个线程不会互相冲突.
不难看出,mutex是semaphore的一种特殊情况(n=1时).也就是说,完全可以用后者替代前者.
但是,因为mutex较为简单且效率高,所以在必须保证资源独占的情况下才会采用这种设计。
操作系统的设计,因此可以归结为三点:
(1)以多进程形式,允许多个任务同时运行;
(2)以多线程形式,允许单个任务分成不同的部分运行;
(3)提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源.
参考链接: https://mp.weixin.qq.com/s/rN_aNty51npDTe_z35y7QQ
Ps: 这里讲线程比喻成了工人,前面中我们讲线程比喻成了流水线.. 不冲突.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 任务运行的三种状态
非阻塞态 -- 就绪态、运行态
阻塞态
1> 运行/执行 (Running) 态: 任务拿到cpu,正在运行
2> 就绪态:
任务已分配到除CPU以外的所有必要的资源,等待被分配cpu,一旦得到cpu,任务就可以立马开始运行
3> 阻塞 (Blocked) 态:
正在执行的任务由于等待某个事件发生而无法执行时,便会放弃cpu而处于阻塞状态.
引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等.
这里以遇见IO为例,任务遇到了IO,拿到cpu也无法运行,必须等到IO操作结束,进入就绪态
提一嘴: cpu受操作系统软件控制. cpu运行任务.
此任务说是进程亦或者线程都没错 但自己要知道运行进程实际上是进程里的一条线程在运行.
[就绪态 --> 运行态]
若此时有多个处于就绪态的任务,ABCD... 操作系统负责协调这件事,将任务A先分配给cpu,此时任务A就处于运行态.
[运行态 --> 就绪态]
当OS认为任务A占用的时间过长了.再或者,有一个优先级比任务A更高的任务B;
任务B就会把cpu抢走了.任务A就会处于就绪态.
[运行态 --> 阻塞态]
(IO是指硬盘开始转,找到相应数据并将数据读到内存的过程)
当任务A遇到IO.此时任务A将进入阻塞态.意味着此时立刻把cpu给处于阻塞态的任务A用,任务A也不会用(任务A在进行IO操作呢,忙不过来).
要知道操作系统肯定不会让cpu闲着..
So,cpu下发指令给硬盘后,操作系统会把任务A一脚踹开,把cpu拿过来运行另一个处于就绪态的任务.
[阻塞态 --> 就绪态 --> 运行态]
阻塞态不能一下子切到运行态,只能等IO操作做完,阻塞完毕..转换成就绪态,拿到操作系统分配的cpu后再转换成运行态.
Q:如何提升任务执行的效率呢?
A:理想情况,cpu一直被此任务占用,任务的IO操作完成后,立马能得到CPU的使用.
但这是不现实的,操作系统不允许cpu资源这样浪费..
我们唯一能控制的就是阻塞.
我们只能在写程序以及部署集群架构的过程中减少任务处于阻塞态的时间,增加任务处于就绪态的时间
(任务处于阻塞态,给它cpu,它也不中用啊)
这样的话,处于就绪态的任务一旦得到cpu就会直接开始运行..任务整体的执行效率就提高了.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Ps: 鸿蒙系统 万物互联.5G时代.分布式软组件..