管程
操作系统中管程有一个重要特性:在一个时刻只能有一个进程使用管程。进程无法执行的时候不能一直占用管程,否则其他进程永远不能使用管程。
使用管程来实现生产者-消费者的问题
进程通信
进程中一般不清楚的有:进程同步和进程通信,区别:
- 进程同步:控制多个进程按照一定顺序执行的。
- 进程通信:进程间传输信息。
这样一般来说为了进程同步所以让进程进行通信,传输一些进程所需要的信息。
管道
管道是通过调用pipe函数创建的
具有以下限制:
- 只支持半双工通信(单向交替传输)
- 只能在父子进程中使用
FIFO
也称为命名管道,去除了管道只能在父子进程中使用的限制
FIFO常用于客户-服务器应用程序中,FIFO用于汇聚点。
消息队列
相比较FIFO,消息队列具有以下优点:
- 消息队列可以独立于读写进程存在,从而避免了FIFO中同步管道的打开和关闭时可能产生的困难
- 避免了FIFO的同步阻塞问题,不需要进程自己提供同步方法
- 读进程可以根据消息类型有选择地接受消息,而不像FIFO那样只能默认地接受。
信号量
是一个计数器,用于为多个进程提供对共享数据对象的访问
共享存储
允许多个进程共享一个给定的存储区,因为数据不需要在进程之间复制。
需要使用信号量用来同步对共享存储的访问。
多个进程可以将同一个文件映射到它们的地址空间从而实现共享内存。
套接字
不同于通信机制,可用于不同机器间的进程通信。
内存管理
虚拟内存
最经典的一句话就是虚拟内存是为了让物理内存扩充为更大的逻辑内存,从而让程序获得更多的可用内存。
虚拟内存采用的是分页技术。
一般来说,操作系统将内存抽象成地址空间。每个程序拥有自己的地址空间,这个地址空间被分割成多个块,每一个块称为一页,这些页被映射到物理内存中,但不需要映射到连续的物理内存,也不需要所有的页都在物理内存中。当程序引用不在物理内存中的页时,由硬件执行必要的映射,将缺失的部分装入物理内存并重新执行失败的指令。
页面置换算法
为什么要有这个页面置换算法,首先,如果访问的页面不在内存中,就发生缺页中断从而将该网页调入到内存中。如果内存无空闲空间,系统必须进行页面置换算法调出一个页面到磁盘对换区中腾出空间。
1、最佳OPT(Optimal repalacement algorithm)
所选择的被换出的页面将最长时间不再被访问
2、最近最久未使用LRU(Least Recently Used)
3、最近未使用(NRU,Not Recently Used)
4、先进先出(FIFO,Fist in First out)
5、第二次机会算法
FIFO算法可能会把经常使用的页面置换出去,当页面被访问(被读写)时设置该页面的R位为1,需要替换的时候,检查最老页面的R位,如果R位是0,那么这个页面既老又没有被使用,可以立刻置换掉,如果是1,就将R位请0,并把该页面放到链表的尾端,修改它的装入时间使它就像刚才装入的一样,然后继续从链表头部开始搜索。
6、时钟
第二次机会需要移动页面,降低效率,时钟算法使用环形链表将页面连接起来,再使用一个指针指向最老的页面。
段页式
程序的地址空间划分成多个拥有独立地址空间的段,每个段上的地址空间划分成大小相同的页。这样既拥有分段系统的共享和保护,又拥有分页系统的虚拟内存功能。
分段
下图为一个编译器在编译过程中建立的多个表,有4个表是动态增长的,如果使用分页系统的一维地址空间,动态增长的特点就会导致覆盖问题的出现。
分段的做法是把每个表分成段,一个段构成一个独立的地址空间。每个段的长度可以不同,并且可以动态增长。
设备管理
磁盘结构
- 盘面(Platter): 一个磁盘有多个盘面。
- 磁道(Track): 盘面上的圆形带状区域,一个盘面可以有多个磁道。
- 扇区(Track Sector): 磁道上的一个弧段,一个磁道可以有多个扇区,它是最小的物理存储单位,目前主要有512bytes与4K两种。
- 磁头(Head): 与盘面非常接近,能够将盘面上的磁场转换为电信号(读),或者将电信号转换为盘面的磁场(写)
- 制动手臂(Actuator arm): 用于在磁道之间移动磁头。
- 主轴(Spindle): 使整个盘面转动。
磁盘调度算法
读写与皮革磁盘块的时间的影响因素
- 旋转时间(主轴转动盘面,使得磁头移动到合适的扇区上)
- 寻道时间(制动手臂移动,使得磁头移动)
- 实际的数据传输时间
其中,寻道时间最长,因此磁盘调度的主要目标是使磁盘的平均寻道时间最短。
1、先到先服务
按照请求的顺序进行调度
优点是公平和简单。缺点就是没有对寻道做任何优化,平均寻道时间可能较长。
2、最短寻道时间优先
优先调度与当前磁头所在磁道距离最近的磁道。
虽然平均寻道时间比较低,但是不够公平。如果新到达的磁道请求总是比一个在等待的磁道请求近,那么在等待的磁道请求会一直等待下去,也就是会出现饥饿现象。具体来说,两端的磁道请求更容易出现饥饿现象。
3、电梯算法
电梯总是保持一个方向运行,直到该方向没有请求为止,然后改变运行方向。
电梯算法(扫描算法)和电梯的运行过程类似,总是按一个方向进行磁盘调度,直到该方向上没有未完成的磁盘请求,然后改变方向。
因为考虑了移动方向,因此所有的磁盘请求都会被满足,解决了SSTF的饥饿问题
链接
编译系统
有一个hello.c的程序
在Unix系统中运行
gcc -o hello hello.c
- 预处理阶段:处理以#开头的预处理命令。
- 编译阶段:翻译成汇编文件
- 汇编阶段:将汇编文件翻译成可重定向目标文件。
- 链接阶段:将可重定向目标文件和printf.o 等单独预编译好的目标文件进行合并,得到最终的可执行目标文件。
静态链接
静态链接器以一组可重定向目标文件为输入,生成一个完全链接的可执行目标文件作为输出。
- 符号解析:每个符号对应于一个函数、一个全局变量或一个静态变量,符号解析的目的是将每个符号引用与一个符号定义关联起来
- 重定位:链接器通过把每个符号定义与一个内存位置关联起来,然后修改所有对这些符号的引用,使得它们指向这个内存位置。
目标文件
- 可执行目标文件:可以直接在内存中执行;
- 可重定向目标文件; 可与其他可重定向目标文件在链接阶段合并,创建一个执行哦目标文件。
- 共享目标文件:这是一种特殊的可重定向目标文件,可以在运行时被动态加载内存并内链。
动态链接
静态库有以下特征
- 当静态库更新时那么整个程序都要重新进行链接
- 对于printf这种标准函数库,如果每个程序都要有代码,这会造成极大浪费
共享库是为了解决静态库的这两个问题而设计的,在linux系统中通常用.so后缀来表示。Windows系统上他们被称为DLL。有以下特点: - 在给定的文件系统中一个库只有一个文件,所有引用该库的可执行目标文件都共享这个文件,它不会被复制到引用它的可执行文件中
- 在内存中,一个共享库的.text节(已编译程序的机器代码)的一个副本可以被不同的正在运行的进程共享。