简单笔记
通信协议又称为接口;
系统调用接口在实现中以软件中断的形式出现:linux使用0x80号中断,windows采用0x2e号中断;
操作系统做什么
操作系统提供抽象的接口,管理硬件资源;
不要让cpu打盹
多道程序---分时系统--->多任务系统
多任务系统:以进程的方式运行,根据优先级的高低得到cpu,超出运行时间会被暂停,换其他进程来进行,抢占式分配,os可以强制剥夺cpu资源并分配给他认为最需要的运行的进程
进程的总体目标是希望每个进程从逻辑上来看都可以独占计算机的资源
设备驱动
OS是硬件的管理和抽象,
UNIX中,硬件设备的访问跟普通的文件形式一样;
WIndow中:
硬件细节都交给了OS中的硬件驱动程序,
硬盘的简单结构
基本存储单位为扇区,每个扇区512字节,硬盘含盘片,有两面,然后每面按同心圆划分为若干个磁道;
现代硬盘普遍采用LBA的方式,所有扇区从0开始编号一直到最后一个扇区,扇区编号称为逻辑扇区号0
内存不够怎么办
虚拟地址空间
物理地址空间
内存分段机制Segmentation
分段基本思路:把一段雨所需内存空间大小的虚拟空间映射到某个地址空间
分段解决的问题:解决了地址隔离问题和程序运行时的地址不确定;
程序以为自己运行在0x00000000~0x000A0000的一段内存上,实际上的物理地址并不是 而只是相同大小的一段物理内存
内存分段无法解决内存使用效率的问题
分段对内存区域的映射是按照程序为单位,若内存不足,被换入出到磁盘的是整个程序,造成大量的磁盘访问操作,从而严重影响速度。
- 程序局部性原理:时间局部性与空间局部性,程序中的某一条指令一旦执行,不久之后该指令可能会被再次执行,访问了某块内存单元,其附近的内存单元也将被访问
内存分页机制
把地址空间人为的分成固定大小的页。每一页的大小的由硬件决定或硬件支持多种页的大小,由操作系统选择决定页的大小
目前基本都是4KB大小的页
- 虚拟空间的虚拟页 物理空间的物理页 磁盘空间的磁盘页
- 页映射可以实现保护,每个页都可以设置权限属性,访问,修改等权限
虚拟存储的实现依靠硬件的支持 大部分硬件采用一个MMU(Memory Management Unit)部件进行映射
虚拟地址到物理地址的转换
CPU-->Virtual Address-->MMU-->Physical Address-->Physical Memory
众人拾柴火焰高
线程基础
线程(Thread),又称轻量级进程( Lightweight Process ,LWP),程序流执行的最小单元
- 一个标准的线程由线程ID,当前指令指针,寄存器集成和堆栈组成
进程由一个或多个线程组成,各个线程之间共享程序的内存空间(包括代码,数据,堆等)及一些进程级的资源 - 多线程的优势:可以互不干扰地并发进行,并共享进程的全局变量和堆的数据
线程的访问权限
可以访问内存里的所有的数据,但线程也拥有自己的私有存储空间
- 栈
- 线程局部存储(Thread Local Storage ,TLS),某些操作系统为线程单独提供的私有空间,通常只有有限的容量
- 寄存器,寄存器是执行流的基本数据,因此为线程私有
C语言来看,数据在线程之间是否私有有如下:
线程私有:局部变量,函数的参数,TLS数据(线程局部存储)
线程之间共享(进程所有):全局变量;堆上的数据;函数里的静态变量;程序代码(任何线程都有权利读取并执行任何代码);打开的文件,A线程打开的文件可以由B线程执行
线程调度 一个不断在处理器上切换不同线程的行为
线程调度中线程至少有三种状态:运行,就绪,等待
线程运行时有一个叫做时间片的东西
Running--开始等待-->Wait--等待结束-->Ready--无运行线程,且本线程被选中-->Runing
|------------时间片用尽-----------------|
线程的优先级调度:线程都有各自的优先级,具有高优先级的线程更早被执行,低的就在最后执行
频繁等待线程称为IO密集型线程,很少等待的线程称为CPU密集型线程 IO密集型线程要比CPU密集型线程容易得到优先级的提升
一个线程等待的时间够长的话它的优先级一定会被提高 从而被执行
- 优先级调度环境下,线程优先级的改变有三种方式
- 用户指定优先级
- 根据进入等待状态的频繁程度提升或降低优先级
- 长时间得不到执行而被提升优先级
- 抢占 线程在用尽时间片之后会被强制剥夺继续执行的权利
线程安全
竞争与原子操作
多线程同时访问一个共享数据;
原子操作:单指令操作
单条指令的执行不会被打断
原子操作仅适用于比较简单的特定场合
同步与锁
防止多个线程同时读写一个数据时出错,将各个线程对同一个数据的访问同步,即在一个线程访问数据未结束的时候,其他线程不得对同一个数据进行访问
- 锁
锁是一种非强制机制,每个线程在访问数据或资源之前首先试图获取锁,并在访问结束之后释放锁,在锁已经被占用的时候试图获取锁时,线程会等待,直到锁重新可用 - 二元信号量 信号量在整个系统可以被任意线程获取释放,同一个信号量可以被系统中的一个线程获取之后由另一个线程释放
最简单的一种锁,两种状态:占用与非占用
它适合只能被唯一一个线程独占访问的资源,当二元信号量处于非占用状态时,第一个试图获取该二元信号量的线程会获得该锁,并将二元信号量置为占用状态,以后其他的所有试图获取该二元信号量的线程将会被等待,直到该锁被释放 - 对于允许多个线程并发访问的资源,多元信号量简称信号量。一个初始值为N的信号量允许N个线程并发访问。线程访问资源的时候首先获取信号量:
- 将信号量值-1
- 如果信号量的值小于0 则进入等待状态 否则继续执行
访问完资源之后,线程释放信号量,进行如下操作 - 信号量值+1
- 如果信号量的值小于1,唤醒一个等待中的线程
互斥量
资源仅允许一个线程访问,并且哪个线程获取的互斥量哪个线程就要释放这个锁
临界区
临界区比互斥量更严格,临界区锁的获取称为进入临界区,锁的释放称为离开临界区
互斥量和信号量在系统的任何进程里都是可见的-->一个进程创建了一个互斥量或信号量,另一个进程试图去获取该锁是合法的
临界区的总用范围仅限于其他进程无法获取该锁 其他都与互斥量相同
读写锁
对于同一个锁读写锁有两种获取方式,共享或独占
- 当锁处于自由状态时,试图以任何一种方式获取锁都能成功,并将锁置于对应的状态
- 如果锁处于共享状态其他线程以共享的形式获取锁仍然会成功,此时这个锁分配给了多个线程
读写锁状态 以共享方式获取 以独占方式获取
自由 成功 成功
共享 成功 等待
独占 等待 等待
条件变量,是一种同步手段,作用类似于一个栅栏
- 线程可以等待条件变量,一个条件变量额可以被多个线程等待
- 线程可以唤醒条件变量,此时某个或所有等待此条件变量的线程都会被唤醒并继续支持
使用条件变量可以让许多线程一起等待某个事件发生,当事件发生的时(条件变量被唤醒)所有的线程可以一起恢复执行
可重入与线程安全
一个函数被重入,表示这个函数没有执行完成
一个函数要被重入只有两种情况:1.多个线程同时执行这个函数 2. 函数自身调用
静态链接
预编译(预处理)-->编译-->汇编-->链接
预编译
预编译过程中展开所有的宏定义,将预编译中导入的文件插入到代码中 删除注释什么的
编译
编译过程就是把预处理完的文件进行一系列的词法分析,语法分析,语义分析以及优化后生成相应的汇编代码
汇编
将汇编代码转换成机器指令
链接
编译器做了什么
编译器就是将高级语言翻译成机器语言的一个工具
编译过程:
扫描-->语法分析-->语义分析-->源代码优化-->代码生成-->目标代码优化
词法分析
源代码程序被输入到扫描器,扫描器运用某种算法(类似于有限状态机)将源代码字符序列分割成一系列的记号
比如 关键字 标识符 字面量 特殊符号
语法分析
语法分析器对扫描器产生的记号进行语法分析从而产生语法树。
以表达式为节点的树
语义分析
语法分析仅仅只能判断代码是否有语法上的错误,不能判断是否真正有意义
编译器只能分析静态语义 即在编译期间可以确定的语义
动态语义 只能在运行期确定的语义
静态语义
通常包括声明和类型的匹配 类型的转换
动态语义
一般指在运行期间出现的语义相关的问题
中间语言生成
编译器对源代码会有一个优化过程
源代码优化器能够将整个语法树转换成中间代码,它是语法树的顺序表示
中间代码使得编译器可以分为前端和后端
编译器前端负责产生机器无关的中间代码,编译器后端将中间代码转化成目标机器代码
方便跨平台编译
目标代码生成与优化
编译器后端主要包括代码生成器和目标代码优化器
代码生成器和优化器
代码生成器将中间代码转化成目标机器代码
目标代码优化器对上述生成的目标代码进行优化
链接 链接器
模块拼装--静态链接
链接过程包括地址和空间的分配,符号决议和重定位
每个模块的源代码文件经过编译器编译成目标文件,目标文件和库一起链接成最终的可执行文件

浙公网安备 33010602011771号