ostep
-
正在运行的程序做的事情:执行指令
-
处理器从内存中获取(fetch)一条指令,对其进行解码(decode)(弄清楚是哪条指令),然后执行操作(比如跳转到函数,访问内存等),完成后,处理器继续执行下一条指令,直到程序最终完成
-
计算机虚拟化就要模拟计算机的主要功能,冯诺依曼的存储程序计算机就是:1.从PC处取一条指令并译码,修改PC 2.执行指令 3.回到1重复执行。
-
PC:program counter 程序计数器(计算机处理器中的 寄存器)
-
程序计数器是用于存放下一条指令所在单元的地址的地方。
当执行一条指令时,首先需要根据PC中存放的指令地址,将指令由内存取到指令寄存器中,此过程称为"取指令"。与此同时,PC中的地址或自动加1或由转移指针给出下一条指令的地址。此后经过分析指令,执行指令。完成第一条指令的执行,而后根据PC取出第二条指令的地址,如此循环,执行每一条指令。
-
-
冯诺依曼体系:
- CPU中央处理器(算术运算和逻辑判断)
- 存储器(外存内存,存储二进制数据)
- 输入设备(用户操作计算机)
- 输出设备(计算机返回结果的设备)
-
CPU中央处理器是干嘛的(算术运算和逻辑判断,CPU内部也有寄存器):
- 处理指令
- 执行操作
- 控制时间
- 处理数据
云
- 云是指你作为接受服务的对象,是云端,不管你在何时何地,都能享受云计算提供的服务。云是网络、互联网的一种比喻说法。
- 云分为私有云、公有云、混合云及行业云等等。云在勾画网络拓扑或网络结构时常见,过去在图中往往用云来表示电信网,后来也用来表示互联网和底层基础设施的抽象。
操作系统:
-
操作系统介绍:(虚拟机,资源管理器)
-
允许程序共享内存
-
程序能与设备交互
-
通过虚拟化让每一个程序或进程独立拥有cpu,内存,并实现共享CPU
-
C标准库都是建立在各类操作系统的标准库上面的,操作系统是第一层,编程语言的标准库是第二层。
-
主要作用:
- 为了更好地运行程序,多个程序并行运行,多个程序共享内存
- 为了可以和硬件设备交互
- 运行程序,分配内存,访问文件,提供可系统调用的api(大多数用户与操作系统交互的主要方式)
- 将底层资源通过接口的方式开放出来,使得应用层不用关注底层实现,实现解耦
-
-
虚拟内存
- 内存就是一个字节数组。要读取(read)内存,必须指定一个地址(address),才能访问存储在那里的数据。要写入(write)或更新(update)内存,还必须指定要写入给定地址的数据。
- 物理地址:真实的内存的地址
-
并发
-
保护
- 隔离:进程彼此隔离是保护的关键
-
可靠性
-
操作系统就是一个”搞管理“的软件
- 管理硬件设备
- 管理软件资源(文件,进程)
- 管理指的一般是:描述(PCB)+组织
进程
-
进程:
-
进程是操作系统中非常核心的一个概念,进程其实是计算机完成工作的一个"过程"
如图所示:进程就是一个正在运行的程序,要想让进程跑起来,就得给这个进程分配一定的系统硬件资源(CPU,内存,磁盘,网络带宽…)
-
-
操作系统如何管理进程:
-
为进程分配虚拟空间
-
假设:
- 0x100 - 0x700 这个内存分给进程1
- 0x100 - 0x700 这个内存分给进程2
-
这里的地址都是操作系统抽象出来的虚拟地址,系统会自动的把这个虚拟地址转换为真实的物理地址
-
为什么不直接访问真实的物理地址,而要创建虚拟地址空间
-
为了一定程度减少内存访问越界带来的后果
-
比如:
-
进程1 的内存范围 0x100 - 0x700,如果我的代码尝试修改 0x701的地址的数据,这个操作就是越界访问(错误的操作)
如果这是一个真实的物理地址,这个修改就真的把 0x701给修改了, 恰好 0x701是进程2 要使用的内存地址,此时进程2 可能就出 bug 了,就会直接奔溃
-
但如果进程访问的是虚拟地址,也尝试修改0x701 此时系统就要针对 0x701 来查询页表,找到对应的物理地址 由于 0x701 已经是非法地址,在 页表中查不到了,系统就会明白,是在越界访问,于是就直接让这个进程出现崩溃(系统就会发送一个型号,这个信号通常会导致进程奔溃),防止影响到其它线程。
-
这样做,就让进程和进程之间相互影响的可能性变小了,隔离性增加了,进程,系统也就更加稳定了。
-
-
-
缺点:但是进程间通信变得困难(如果要想相互交流沟通,就需要使用一些特殊的手段,比如:文件,管道(是内核中提供的一个队列),消息队列,信号量等)
-
-
管理指的一般是:描述(PCB)+组织
- PCB:进程的控制块,C语言的一个结构体,一个结构体对象就对应一个进程,将存储关于进程信息的个体结构称为进程控制块 - 组织:使用一定的数据结构来组织,常见作法就是使用双向链表 - 查看进程列表:遍历操作系统内核中的这个链表,并显示属性 - 创建一个进程:创建一个PCB对象,并加入到内核的链表中 - 销毁一个进程:把这个PCB对象从内核链表中删除 - 进程的属性 + pid:一个进程的身份标识(唯一) + 内存指针:描述了这个进程使用的内存空间是哪个范围(虚拟地址空间) + 文件描述符表:描述这个进程打开了哪些文件
-
-
-
执行:
- 并发式执行:切换进程
- 并行式执行:多个CPU运行多个进程(4核或者8核CPU相当于4或8个分身)
- 操作系统进行进程调度的时候,是并发并行综合使用
-
-
管道(半双工通信):
- 管道只能一端读取另一端写入
- 操作系统分为内核态和用户态,管道就是在内核中开辟一块缓冲区,不同的进程通过对这个缓冲取进行读写操作实现IPC。
- 以Linux下的为例吧,管道是一种进程间通信的方式,在linux中分为有名管道和无名管道。有名管道就是把一个进程的输出写到一个文件中,再把此文件作为另一个进程的输入。 无名管道也是如此,只不过这个管道文件不直接可见而已,通常无名管道都作为一个进程组的形式完成,如ls | grep 'a',这就是一种进程间单向的通信方式。
- 匿名管道,半双工通信,只能在父子或者兄弟进程间使用.,
- 命令流管道s_pipe: 全双工。父子兄弟间使用。
- 命名管道FIFO:半双工通信。任意进程间使用
发展:
-
早期操作系统:
- 简单服务:只是一些库,一组常用函数库(让OS提供 I/O 这样的API,而不是让系统的每个程序员都编写低级 I/O 处理代码)
- 批处理,先把一些工作准备好,然后由操作员以分批方式运行(运行一个程序,如决定运行作业的顺序)
系统调用
-
超越库:
- 操作系统运行代码是特殊的,控制设备
- 将一个文件系统实现为一个库,并允许任何应用程序访问磁盘所有文件,让隐私的概念消失没有意义
- 系统调用:添加一些特殊的硬件指令和硬件状态,让向操作系统过渡变为更正式、受控的过程
-
系统调用和过程调用区别:
- 系统调用将控制转移(跳转)到OS中,同时提高硬件特权级别(hardware privilege level)。用户应用程序以所谓的用户模式(user mode)运行,这意味着硬件限制了应用程序的功能。例如,以用户模式运行的应用程序通常不能发起对磁盘的I/O请求,不能访问任何物理内存页或在网络上发送数据包。在发起系统调用时 [通常通过一个称为陷阱(trap)的特殊硬件指令],硬件将控制转移到预先指定的陷阱处理程序(trap handler)(即预先设置的操作系统),并同时将特权级别提升到内核模式(kernel mode)。在内核模式下,操作系统可以完全访问系统的硬件,因此可以执行诸如发起I/O请求或为程序提供更多内存等功能。当操作系统完成请求的服务时,它通过特殊的陷阱返回(return-from-trap)指令将控制权交还给用户,该指令返回到用户模式,同时将控制权交还给应用程序,回到应用离开的地方。
-
多道程序:
-
操作系统不是一次只运行一项作业,而是将大量作业加载到内存中并在之间快速切换,提高CPU利用率(I/O 设备很慢,浪费CPU实践)
-
系统中有一些操作很慢,这个时候可能只是读取或者传输,交换,会导致cpu空转。 因此某一个程序处于这种状态时,先将其寄存回内存,然后切换另一个程序使用cpu,当另一个程序要进入不需要cpu计算时,把另一个程序调回,把这个程序寄存。 这是一种防止计算机器空转的好方法。
-
CPU空转:
while(true){ //do nothing } //大家一看,这就是个啥事儿也没做的死循环啊,跑起来CPU会占用100%的。没错,这就是所说的“CPU空转”。
-
在 CPU 的角度看进程行为的话,可以分为两类:
- CPU 消耗型:此类进程就是一直占用 CPU 计算,CPU 利用率很高
- IO 消耗型:此类进程会涉及到 IO,需要和用户交互,比如键盘输入,占用 CPU 不是很高,只需要 CPU 的一部分计算,大多数时间是在等待 IO
CPU 消耗型进程需要高的吞吐率,IO 消耗型进程需要强的响应性,这两点都是调度器需要考虑的。
为了更快响应 IO 消耗型进程,内核提供了一个抢占(preempt)机制,使优先级更高的进程,去抢占优先级低的进程运行。
-
多道程序意味着一次加载很多程序到内存,一个程序进行较慢的IO操作时,马上切换到另一个程序。程序切换带来两个问题,一是内存保护,二是并发控制,就是时间片轮转、寄存器上下文切换、锁和返回等问题。
-
-
受限:
-
1、一个进程必须能够执行一些受限制的操作,但是又不能让进程完全控制整个系统,操作系统和硬件如何共同协作实现这一需求?
程序在用户态模式(User Mode)下操作受到限制,只有进入内核态(Kernel Mode)才能执行受限制的指令。用户模式下的程序调用系统调用会产生软中断,硬件将该进程的寄存器保存到内核栈中并跳到陷阱处理程序,然后在内核模式下的操作系统先处理陷阱,接着做系统调用的工作,最后从陷阱返回,硬件再从内核栈中恢复寄存器并跳转到程序计数器,进程继续运行。
-
2、一个进程在CPU上运行就意味着操作系统没有运行,操作系统又将如何重新获取对CPU的控制权?
① 协作方式:当⑴进程进行系统调用或者⑵系统发生某种非法操作时,操作系统重新获得对CPU的控制权(regain control)。 ② 非协作方式:时钟中断(timer Interrupt)。时钟中断(timer interrupt)[M+63]。时钟设备可以编程为每隔几毫秒产生一次中断。产生中断时,当前正在运行的进程停止,操作系统中预先配置的中断处理程序(interrupt handler)会运行。此时,操作系统重新获得CPU的控制权,因此可以做它想做的事:停止当前进程,并启动另一个进程。
-
3、上下文切换的概念及过程
概念:操作系统要做的就是为当前正在执行的进程保存一些寄存器的值(例如,到它的内核栈),并为即将执行的进程恢复一些寄存器的值(从它的内核栈)。 过程:为了保存当前正在运行的进程的上下文,操作系统会执行一些底层汇编代码,来保存通用寄存器、程序计数器,以及当前正在运行的进程的内核栈指针,然后恢复寄存器、程序计数器,并切换内核栈,供即将运行的进程使用。通过切换栈,内核在进入切换代码调用时,是一个进程(被中断的进程)的上下文,在返回时,是另一进程(即将执行的进程)的上下文。当操作系统最终执行从陷阱返回指令时,即将执行的进程变成了当前运行的进程。至此上下文切换完成。
-
4、由时钟中断机制产生的并发问题的简单解决方案
① 禁止中断(disable interrupt):在时钟中断过程中,禁止再次时钟中断。此方法可能导致时钟中断的丢失。 ② 锁(locking):这使得多个活动可以同时在内核中进行,特别适用于多处理器。