操作系统:是一个大型的程序系统
简而言之:管理并调度资源;为用户提供接口
不同视角理解
操作系统地位:
操作系统特性
进程管理
存储管理:为应用程序运行高效提供内存空间;支持多道程序设计
设备管理:提供统一的设备使用接口,管理设备分配和使用
文件管理:文件和目录管理,提供简便统一的信息存取和管理方法,并解决信息共享、数据的存取控制等问题
吞吐率:在单位时间内处理信息的能力
响应能力:从接收数据到输出结果的时间间隔
资源利用率:设备使用的频度
可移植性:改变硬件环境仍能正常工作的能力:代码修改量
可靠性:发现、诊断和恢复系统故障的能力
计算机硬件发展的四个经典阶段
操作系统发展的四个典型阶段:
手工操作、单道批处理、多道批处理、分时操作系统
手工操作
单道批处理系统
多道批处理系统
分时操作系统
实时操作系统/嵌入式操作系统
背景
特点
微机操作系统(PC机)
多处理机操作系统
定义
并行系统;紧耦合系统
包含两个或多个功能相当的处理器
共享内存,共享I/O,共享外设
一个操作系统控制
特点:
网络操作系统
定义
独立自治的计算机相互连接形成一个集合
普通OS+网络通信+网络服务
Unix/Linux/Win
特点
局限性
分布式操作系统
适合学习和研究的简化操作系统:Minix OS
推荐学习的大型开源操作系统:Linux
OS的设计和实现思路
定义:模块化结构/单体内核结构/宏内核结构。操作系统由大量过程构成。每个过程都有明确参数列表、返回值类型。大多数过程是可以相互间调用。
以模块为基本单位构建:每个模块具有特定的功能
优点
缺点
实例
UNIX:单体内核,对外提供一组系统调用,设备驱动与内核其他部分分开
Linux:单体内核,支持动态可安装模块,模块可以在内核运行时编译或安装
定义:功能模块按调用次序排成若干层,各层单向依赖或单向调用
分层原则
优点
客户:应用程序
服务器:操作系统
微内核:足够小,提供OS最基本的核心功能和服务
核外服务器:完成OS的绝大部分功能,等待客户提出请求
实例OS
Windows NT内核
实质 | 优点 | 缺点 | 代表 | |
---|---|---|---|---|
宏内核 | 将图形、设备驱动及文件系统等功能 全部在内核中实现,和内核运行在同一地址空间 | 减少进程间通信和状态切换的系统开销,获得较高的运行效率 | 内核庞大,占用资源较多且不易剪裁;系统的稳定性和安全性不好。 | UNIX Linux |
微内核 | 只实现OS基本功能,将图形、文件系统、设备驱动及通信功能放在内核之外。 | 内核精练,便于剪裁和移植;系统服务程序运行在用户地址空间,系统的稳定性和安 全性较高 | 用户状态和内核状态 需要频繁切换,从而导致系统效率不如单体内核。 | Minix WinCE |
操作系统基本硬件结构:CPU、内存、中断、时钟
操作系统安全问题
解决方案
态:即CPU的工作状态。是对资源和指令使用权限的描述
硬件要求
特权指令
硬件和OS对CPU的观察
A | B | C | D | ||
---|---|---|---|---|---|
硬件→ | 核心态 | K | K | ||
硬件→ | 用户态 | U | U |
Interl CPU的态
段描述符
字节7 | 字节6 字节5 | 字节4 字节3 字节2 | 字节1 字节0 |
---|---|---|---|
段基址1 | 段属性+一部分段限长 | 段基址2 | 段限制长2 |
字节6字节5
7 | 6 | 5 | 4 | 3210 | 7 | 65 | 4 | 3210 |
---|---|---|---|---|---|---|---|---|
G | D | 0 | AVL | 段限长1 | P | DPL | S | TYPE |
程序段A访问程序段B时的权限检查(态):JMP B, CALL B
当前特权级CPL:Current Privilege Level
请求特权级RPL:Requested Privilege Level
描述符特权级DPL:Descriptor Privilege Level
特权级(低→高) | 特权级(高→低) | 相同特权级 | |
---|---|---|---|
一致代码段 | Y | N | Y |
非一致代码段 | N | N | Y |
数据段 | N | Y | Y |
Unix/Linux OS:仅支持Ring0,Ring1和Ring3
Windows:仅支持Ring0和Ring3
用户态向核态转换
核态向用户态转换:一般是中断返回RET
定义:存储程序和数据的部件
分类依据 | |||
---|---|---|---|
按与CPU的联系 | 主存:直接和CPU交换信息 | 辅存:不能直接和CPU交换信息 | |
按存储元的材料 | 半导体存储器:常作主存 | 磁存储器:磁带,磁盘 | 光存储器:光盘 |
按存储器读写工作方式 | RAM | ROM |
理想存储:速度快,容量大,成本低
实际存储:寄存器、高速缓存(CACHE)、主存、磁盘
工作
定义:指CPU对突发的外部事件的反应过程或机制。CPU收到外部信号(中断信号)后,停止当前工作,转去处理该外部事件,处理完毕后回到原来工作的 中断处(断点)继续原来的工作
作用
实现并发活动
实现实时处理
故障自动处理
中断源:引起系统中断的事件称为中断源
中断类型
断点:程序中断的地方,将要执行的下一指令的地址 CS:IP
现场:程序正确运行所依赖的信息集合。PSW(程序状态字)、PC、相关寄存器
进入中断服务程序:破坏主程序的现场
现场的两个处理过程
中断响应过程
栈
外部中断/INT指令:PUSH SS、PUSH SP、PUSHF、PUSH CS、PUSH IP
IRET:POP IP、POP CS 、POPF 、POP SP 、POP SS(通过IRET进入特定的代码段/任务)
堆栈不变无特权级变化,堆栈变表示有特权级变化
中断响应的实质
定义:以固定间隔产生时钟信号,提供计算机所需的节拍
作用:时间片;提供绝对时间;提供预定的时间间隔;WatchDog
类型:绝对时钟;相对时钟
用户环境:用户工作的软件环境,(桌面环境、命令行环境)
用户环境构造:按照用户要求和硬件特性安装和配置操作系统(提供操作命令和界面,提供系统用户手册)
定义:根据硬件环境和用户需要,配置和构建操作系统。
前提
Linux操作系统的生成
获取Linux内核的源代码(最好是当前版本)
选择和启动内核配置程序
根据需要配置内核模块和参数
重新编译新的内核
编译和安装模块
启动新内核
cp bzImage /boot/bzImage
GRUB(与发行版本有关):配置/boot/grub/grub.conf
title newLinux build by Zhang San Feb.28.2019
root (hd0,1)
kernel /boot/bzImage ro root=/dev/hda2
LILO(早期版本):配置/etc/lilo.conf后lilo使之生效
image=/boot/bzImage
label=newLinux build by Zhang San Feb.28, 2012
实模式:实地址模式,REAL MODE
实模式1M空间 | |
---|---|
前640K[0000-9FFF] | 基本内存 |
中间128K[A000-BFFF] | 显卡内存 |
末尾256K[C000-FFFF] | BIOS |
保护模式:(内存保护模式,PROTECT MODE)
定义:Basic I/O System,基本输入输出系统
BIOS256K空间 | |
---|---|
[C000-C7FF] | 显卡BIOS |
[C800-CBFF] | IDE控制器BIOS |
[F000-FFFF] | 系统BIOS |
功能
定义:当用户按下PowerOn或者Reset键加电,开始执行FFFF0单元的指令(JUMP POST),开始自检
定义:开机时将OS载入内存并运行为用户建立用户环境
两种方式:现场引导方式(OS文件存储在本都存储设备)、逐步引导方式(滚雪球方式)
定义:从加电到用户工作环境准备好的过程
目的:把OS内核装入内存并使之开始工作接管计算机系统
过程
目的:OS内核初始化系统的核心数据
典型工作:
目的:为用户使用系统作准备,使系统处于待命状态。
主要工作
构成
启动过程
启动过程
Linux
启动过程
主启动扇区MBR::BootLoader或更强功能的启动管理
启动扇区:BootLoader,引导OS
MBR工作
MBR的结构
MBR结构 | |
---|---|
446B[000-1BD] | boot loader |
64B[1BE-1FD] | 硬盘分区表 |
2B[1FE-1FF] | Magic number 55 AA |
Boot Loader:三部分
安装过程
多操作系统安装:安装顺序;MBR重新或MBR追加
定义:OS提供给用户控制计算机的机制,又称用户接口
用户界面类型
定义:shell时操作系统与用户交互的界面
特点:Shell表现为通过控制台执行用户命令的方式;Shell本身不执行命令,仅仅是组织和管理命令
分类:Bsh Csh Ksh(Bsh+Csh) Bash(Bsh升级+Ksh)
Bsh的主要功能
命令行编辑功能
命令和文件名补全功能:tab键
命令历史功能
命令别名功能
提供作业控制功能
具有将命令序列定义为功能键的功能
管道与重定向
标志输入/输出
输入/输出文件 | 设备 | 文件编号 |
---|---|---|
标准输入文件 | 键盘 | 0 |
标准输出文件 | 显示器 | 1 |
标准错误输出文件 | 显示器 | 2 |
重定向
管道操作
Shell Script脚本编程
脚本
功能:脚本(Script)通过类似程序的方式执行具有一定逻辑顺序的命令序列完成较复杂的功能和人机交互
运行方法
定义:操作系统内核为应用程序提供的一系列服务/函数
例如:printf、exit、fopen、fgetc、21H(09)
特点
系统调用的实现
DOS:INT 21H
Linux:INT 80H
执行过程
隐式系统调用
特点
实质
工作原理
系统调用封装在unistd.h中
定义:进程是程序在某个数据集合上的一次运行活动
数据集合:软/硬件环境,多个进程共存/共享的环境
进程特征:
程序 | 进程 | |
---|---|---|
动静 | 程序是静态的:一组指令的有序集合 | 进程是动态的:程序的一次执行过程 |
持久 | 程序是长存的:在介质上长期保存 | 进程是暂存的:在内存驻留 |
对应 | 一个程序可能有多个进程 | 一个程序可能有多个进程 |
进程的类型
进制的状态
进程状态的变化
变化 | 服务:系统调用/IO操作,信号:事件 |
---|---|
就绪→运行 | 进程调度 |
运行→就绪 | 时间片到;被抢占 |
运行→阻塞 | 服务请求;等待信号 |
阻塞→就绪 | 服务完成;信号来到 |
具有新建(new)和终止(terminate)状态的进程状态
支持挂起(suspend)和解挂(resume)操作的进程状态
活动阻塞(正常阻塞)静止阻塞(阻塞时挂起)
活动就绪(正常就绪)静止就绪(就绪时挂起)
变化 | 服务:系统调用/IO操作,信号:事件 |
---|---|
活动就绪→运行 | 进程调度 |
运行→活动就绪 | 时间片到;被抢占 |
运行→活动阻塞 | 服务请求;等待信号 |
活动阻塞→活动就绪 | 服务完成;信号来到 |
活动就绪→静止就绪 | 挂起 |
静止就绪→活动就绪 | 解挂 |
运行→静止就绪 | 挂起 |
静止阻塞→活动阻塞 | 解挂 |
活动阻塞→静止阻塞 | 挂起 |
静止阻塞→静止就绪 | 信号来到 |
Linux的进程状态
ps aux查看STAT R=TASK_RUNNING S=TASK_UNINTERRUPTIBLE I=空闲 Z=TASK_ZOMBIE
定义:描述进程的状态、资源、和相关进程的关系的一种数据结构;PCB是进程的标志,随进程创建和撤销
进程=程序+PCB
Linux的进程控制块结构体 task_struct
Linux进程标识
进程的上下文切换
进程A | OS | 进程B |
---|---|---|
执行 | 空闲 | |
执行→空闲 | 保存PCB(A) | 空闲 |
空闲 | 空闲 | |
空闲 | 加载PCB(B) | 空闲→执行 |
空闲 | 执行 | |
空闲 | 执行 | |
空闲 | 保存PCB(B) | 执行→空闲 |
空闲 | 空闲 | |
空闲→执行 | 加载PCB(B) | 空闲 |
执行 | 空闲 |
定义:在进程生存全期间,对其全部行为的控制
四个典型的进程控制:创建进程;撤消进程;阻塞进程;唤醒进程
原语:由若干指令构成的具有特定功能的函数,具有原子性,其操作不可分割。
进程控制原语:创建原语;撤消原语;阻塞原语;唤醒原语
功能:创建一个具有指定标识(ID)的进程
参数:进程标识、优先级、进程起始地址、CPU初始状态、资源清单等
过程
功能:撤消一个指定的进程,收回进程所占有的资源,撤消该进程的PCB
参数:被撤消的进程名(ID)
时机:正常结束;异常结束;外界干预
过程
功能:停止进程执行,变为阻塞
参数:阻塞原因(不同原因构建有不同的阻塞队列)
时机
过程
功能:唤醒处于阻塞队列当中的某个进程
参数:被唤醒进程的标识
时机
system(“c:\test.exe”);
WinExec(“c:\test.exe”, SW_SHOWMAXIMIZED);
ShellExecute(NULL, “open”, “c:\test.exe”);
CreateProcess(NULL, “c:\test.exe”, NULL, NULL, false, 0, NULL, NULL, NULL, &si, &pi)
CreateProcess = system + WinExec + ShellExecute
CreateProcess:创建新进程
void ExitProcess(UINT uExitCode);
void TerminateProcess(HANDLE hProcess, UINT uExitCode);
pid_t fork(void); 子进程中,pid = 0;父进程中,pid > 0
父进程和子进程
fork函数执行流程
init进程
Unix
Linux
功能:装入一个指定的可执行程序运行,使子进程具有和父进程完全不同的新功能
流程
exit:调用void exit(int status)终结进程,进程终结时要释放资源并向父进程报告
wait:进程调用wait(int &status)阻塞自己
sleep:Sleep(int nSecond),进程暂停执行nSecond秒
定义:线程是进程内的一个执行路径
特点
线程的应用如果把程序中某些函数创建为线程,那么这些函数将可以并发运行
进程=资源集+线程组
线程技术典型适用场景
进程的互斥关系:多个进程由于共享具有独占性的资源,必须协调各进程对资源的存取顺序:确保没有任何两个或以上的进程同时进行资源存取
临界资源:一次只允许一个进程独占访问(使用)的资源,是资源。临界资源的访问具有排他性
临界区:进程中访问临界资源的程序段,是程序。并发进程不能同时进入“临界区”
临界区四个访问原则
访问临界区方法
进程的同步关系:若干合作进程为了共同完成一个任务,需要相互协调运行步伐:一个进程A开始某个操作之前要求另一个进程B必须已经完成另一个操作,否则进程A只能等待。
另一种解释:合作进程中某些操作之间需要满足某种先后关系或某个操作能否进行需要某个前提条件满足,否则只能等待
基本原理
锁机制未满足让权等待
信号灯定义为二元矢量(S,q)
S:整数,初值非负(S又称信号量)
q:队列(进程PCB集合),初值为空集
P操作:申请资源,当前资源不足则阻塞排队,排队的进程数为-S
P(S, q) {
S--;
if (S < 0) {
Insert(Caller, q);
Block(Caller);
转调度函数();
}
}
V操作:释放资源,意味着肯定有资源出现,S<=0意味着有+1之前有进程在排队,选一个运行
V(S, q) {
S++;
if (S <= 0) {
Remove(q, PID);
Wakeup(PID);
}
}
S1 = 0 门是否关好 S2 = 0 车是否停稳
司机 | 售票员 |
---|---|
关门 | |
V(S1) | |
P(S1) | |
起步; | |
行驶; | 售票 |
停车; | |
V(S2); | |
P(S2) | |
开门 |
一群生产者通过缓冲区向一群消费者提供产品,共享缓存区
互斥关系 int mutex = 1
同步关系
int Data = 0
int Space = 5
producer() {
while(1) {
生产1个数据;
P(Space);
P(mutex);
存1个数据到缓冲区;
V(mutex);
V(Data);
}
}
consumer() {
while(1) {
P(Data);
P(mutex);
取1个数据到缓冲区;
V(mutex);
V(Space);
消费一个数据;
}
}
有读者读书;有多个读者;有编者编书;有多个编者
互斥关系int w_mutex = 1
int cnt = 1, r_mutex = 1
读者优先:当存在读操作时,编操作有可能将被无限延迟
Readder() {
while(1) {
P(r_mutex); // 保证修改cnt的操作原子性
if (++cnt == 1) P(w_mutex);
V(r_mutex); // 保证修改cnt的操作原子性
读书;
P(r_mutex);
if (--cnt == 0) V(w_mutex);
V(r_mutex)
}
}
Editor() {
while (1) {
P(w_mutex);
编书;
V(w_mutex);
}
}
写者优先:当有读操作时,如果有编者请求访问,这时应禁止后续的读操作请求应让当前读操作执行完毕后立即让编者进程执行。 只有在无编者操作的情况下才允许读进程再次运行
同步关系:如果串行顺序是 R1 W1 R2的话,不能让W1被R2挤占 int editor_first = 1
Reader() {
while(1) {
P(editor_first); // 保证读写公平
P(r_mutex); // 保证修改cnt的操作原子性
if (++cnt == 1) P(w_mutex);
V(r_mutex); // 保证修改cnt的操作原子性
V(editor_first); // 保证读写公平
读书;
P(r_mutex);
if (--cnt == 0) V(w_mutex);
V(r_mutex)
}
}
Editor() {
while (1) {
P(editor_first); // 保证读写公平
P(w_mutex);
编书;
V(w_mutex);
V(editor_first); // 保证读写公平
}
}
定义:两个或多个进程无限期地等待永远不会发生的条件的一种系统状态(每个进程都永远阻塞)
另一个定义:在两个或多个进程中,每个进程都已持有某种资源,但又继续申请其它进程已持有的某种资源。此时每个进程都拥有其运行所需的一部分资源,但是又都 4不够,从而每个进程都不能向前推进,陷于阻塞状态。这种状态称死锁。
原因:
例子:假如顺序不当,如果Space=0,生产者获得了mutex权利但不能放数据,等待消费者消费;但消费者无法获得mutex所以无法消费。结果死锁
producer() {
while(1) {
生产1个数据;
p(mutex); // P(Space);
p(Space); // P(xmutex);
存1个数据到缓冲区;
V(mutex);
V(Data);
}
}
consumer() {
while(1) {
P(Data);
P(mutex);
取1个数据到缓冲区;
V(mutex);
V(Space);
消费一个数据;
}
}
死锁结论
死锁的必要条件
定义:通过设置某些限制条件,破坏死锁四个必要条件中的一个或多个,来防止死锁
操作:
特点:(早期)广泛使用。
缺点:由于限制太严格,导致资源利用率和吞吐 量降低
定义:在资源的分配过程中,用某种方法分析该次分配是否可能导致死锁?若会则不分配;若不会就分配
银行家算法:只需要较弱的限制条件,可获得较高的资源利用率 和系统吞吐量。缺点:实现较难
定义:允许死锁发生,但可通过检测机制及时检测出死锁状态,并精确确定与死锁有关的进程和资源,然后采取适当措施,将系统中已发生的死锁清除,将进程从死锁状态解脱出来
检测方法:复杂
恢复方法:撤消或挂起一些进程,以回收一些资源
缺点:难
鸵鸟策略:视而不见,交给用户
调度定义:在一个队列中,按某种策略选择一个最合适个体
调度分类
进程调度定义:在合适的时候以一定策略选择一个就绪进程运行
进程调度的目标:部分原则之间存在自相矛盾
1和2:交互程序和后台程序的矛盾
1和3:响应速度快CPU频繁切换;系统吞吐量大CPU有效工作时间长
2和5:处理时间尽快则特定进程优先;但是部分进程会饥饿
量化进程调度指标
周转时间t | 平均周转时间 | 带权周转时间w | 平均带权周转时间 | |
---|---|---|---|---|
定义 | 进程提交给计算机到完成所花费的时间 | |||
计算 | t=tc-ts=进程完成时间-进程提交时间 | t=Σti/n | w=t/tr=t/进程运行时间 | w=Σwi/n |
意义 | 说明进程在系统中停留时间的长短 | 平均周转时间越短,意味着这些进程在系统内停留的时间越短,因而系统吞吐量也就越大,资源利用率也越高 | 进程在系统中的相对停留时间 |
算法:按照作业进入系统的时间先后次序来挑选作业。先进入系统的作业优先被运行
特点
算法:参考运行时间,选取时间最短的作业投入运行
特点
响应比:作业的响应时间和与运行时间的比值
响应比=响应时间/运行时间=(等待时间 + 运行时间)/运行时间= 1 + 等待时间/运行时间 = 加权周转时间w
算法:调度作业时计算作业列表中每个作业的响应比,选择响应比最高的作业优先投入运行
特点
算法:根据进程优先数,把CPU分配给最高的进程。进程优先数 = 静态优先数 +动态优先数
静态优先数:进程创建时确定,在整个进程运行期间不再改变
动态优先数:动态优先数在进程运行期间可以改变
算法
优点
时间片大小
改进
定义:当一进程正在CPU上运行时,若有更高优先级的进程需要运行,系统分配CPU的方法
非剥夺方式:让正在运行的进程继续执行,直到该进程完成或发生某事件而进入“完成”或“阻塞”状态时,才把 CPU分配给新来的更高优先级的进程。
剥夺方式:当更高优先级的进程来到时,便暂停正在运行的进程,立即把CPU分配给新来的优先级更高的进程。
特点
存储器功能需求:容量大、速度快、信息永久保存、多道程序并行
实际存储器体系:三级存储体系:CPU→Cache(快、小、贵)→内存(适中)→辅存(慢、大、廉)
基本原理:当内存太小不够用时,用辅存来支援内存;暂时不运行的模块换出到辅存上,必要时再换入内存。
多道程序并行的问题
存储管理的功能
定义:也叫地址重定位、地址重映射。把程序中的地址变换成真实的内存地址的过程。(虚拟地址/虚地址/逻辑地址)→(实地址/物理地址)
虚拟地址/源程序包括:地址,变量,标号,函数名
方式:固定地址映射、静态地址映射、动态地址映射
定义:编程或编译时确定逻辑地址和物理地址映射关系
特点
定义:程序装入时由操作系统完成逻辑地址到物理地址的映射。保证在运行之前所有地址都绑定到主存
逻辑地址:VA(Virtual Addr.)
装入基址:BA(Base Addr.)
物理地址:MA(Memory Addr.)
MA = BA + VA
特点
定义:在程序执行过程中把逻辑地址转换为物理地址,例如 MOV AX,[500]; 访问500单元时执行地址转换
基址寄存器:BAR(重定位寄存器),运行现场的数据
MA = BA([BAR]) + VA
实现方案:进程进入主存时根据进程的现场设置BAR,引用具体命令时,用BAR重定位。
连续的进程空间用几个不连续的物理块存放的方法
特点
缺点:需要MMU(内存管理单元)支持,软件复杂
问题
虚拟存储的基本原理(问题1的解决)
程序局部性原理
虚拟存储前提:足够的辅存;适量的内存;地址变换机构
虚拟存储的应用:页式虚拟存储,段式虚拟
定义:为程序运行分配足够的内存空间
问题
定义:保证在内存中的多道程序只能在给定的存储区域内活动并互不干扰
防止访问越界、防止访问越权
方法
方法:单一区存储管理(不分区存储管理);分区存储管理;内存覆盖技术;内存交换技术
定义:用户区不分区,完全被一个程序占用(DOS)
优点:简单,不需复杂硬件支持,适于单用户单任务OS
缺点:程序运行占用整个内存,内存浪费,利用率低
定义:把用户区内存划分为若干大小不等的分区,供不同程序使用;最简单的存储管理,适合单用户单任务系统。
分类:固定分区;动态分区
定义:把内存固定地划分为若干个大小不等的分区供各个程序使用。每个分区的大小和位置都固定,系统运行期间不再重新划分
分区表:记录分区的位置、大小和使用标志
区号 | 大小 | 起址 | 占用标志 |
---|---|---|---|
1 | 16K | 20K | 0/1 |
2 | 32K | 36K | 0/1 |
3 | 64K | 68K | 0/1 |
4 | 124K | 132K | 0/1 |
特点
缺点
应用建议:程序大小、个数、装入顺序等都固定时的情景;根据分区表安排程序装入顺序
定义:在程序装入时创建分区,使分区的大小刚好与程序的大小相等
特点:分区动态建立;分区的个数和大小均可变;存在内存碎片
分区的选择(放置策略)
首次适应算法 | 最佳适应算法 | 最坏适应算法 | |
---|---|---|---|
空闲区表排序 | 空闲区首址递增排序 | 空闲区大小递增排序 | 空闲区大小递减排序 |
目的 | 尽可能先利用低地址空间 | 尽量选中满足要求的最小空闲区(最容易产内存碎片) | 尽量使用最大的空闲区,一次查找 |
分区的分配
功能:从用户选中的分区中分配/分割所需大小给用户(从低地址开始);剩余部分作为空闲区登记在空闲区表
分区的回收
功能:回收程序占用的分区,将其适当处理后登记到空闲区表中;若释放区与现有空闲区相邻则合并
定义:在较小的内存空间中运行较大的程序,将内存分为常驻区和覆盖区
常驻区:被某段单独且固定地占用的区域,核心段
覆盖区:能被多段共用(覆盖)的区域,可划分多个
工作原理
意义:减少程序对内存需求
例子
原理:内存不够时把进程写到磁盘;当进程要运行时重新写回内存
优点:增加进程并发数;不考虑程序结构
缺点:换入和换出增加CPU开销;对换单位太大(整个进程)
对换问题:程序换入时的地址重定位;减少对换传送的信息量;外存对换空间的管理方法
OS:UNIX、Linux、Windows都采用了Swapping
特点 | 缺点 |
---|---|
源程序直接使用内存物理地址 | 程序间容易访问冲突 |
程序必须全部装入内存才能运行 | 内存太小程序无法运行 |
程序占用连续的一片内存 | 产生内存碎片 |
多程序同时运行容易相互干扰 | 不安全 |
因此需要虚拟内存技术
定义:虚拟内存是面向用户的虚拟封闭存储空间
目标:
实现思路
典型虚拟内存管理方式:页式、段式、段页式
定义:把进程空间(虚拟)和内存空间都划分成等大小的小片(4K,2K,1K)
页:进程的小片
页框:内存的小片
页面大小的选择
进程装入和使用内存的原则
虚拟地址的种类:页式地址
虚拟地址VA
页面映射表:记录页与页框(也称块)之间的对应关系。也叫页表
页号 | 页框号 | 页面其他特性 |
---|---|---|
0 | 5 | 含存取权限在内的其他特性:读、写、执行 |
1 | 65 | 是否被访问过? |
2 | 13 | 是否被修改过? |
页表的建立
页表的扩充
中断位I:标识该页是否在内存:若I=1,不在内存;若I =0,在内存
辅存地址:该页在辅存上的位置
页号 | 页框号 | 中断位I | 辅存地址 |
---|---|---|---|
1 | |||
0 |
访问位:标识该页最近是否被访问:0,最近没有被访问 1,最近已被访问
修改位:标识该页的数据是否已被修改:0,该页未被修改 1,该页已被修改
页号 | 页框号 | 访问位 | 修改位 |
---|---|---|---|
1 | 0 | ||
0 | 1 |
页式地址映射
防止越界访问其他进程:检查访问的目的页号X是否在进程内
检查标准:0 <= X < 虚拟页数
越界则产生越界中断
定义:快表是普通页表(慢表)的部分内容的复制
工作机制:地址映射时优先访问快表,合理的页面调度策略能使快表具有较高命中率
在页表中填上共享的页框号,从而实现页面共享,共享页面在内存只有一份真实存储
例子如文本编辑器:150KB代码段和50KB数据段,有10进程并发执行该文本编辑器
定义:在地址映射过程中,当所要访问的目的页不在内存时,则系统产生异常中断
缺页中断处理程序:中断处理程序把所缺的页从页表指出的辅存地址调 入内存的某个页框中,并更新页表中该页对应的页框号以及修改中断位I为0
缺页率 f = 缺页次数 / 访问次数
影响缺页次数的因素
缺页中断与普通中断
页面抖动:页面在内存和辅存间频繁交换的现象;“抖动”会导致系统效率下降
好的淘汰策略:具有较低的缺页率(高命中率);页面抖动较少
LRU的实现
LFU的实现
最佳算法OPT | 先进先出FIFO | 最久未使用LRU | 最不经常使用LFU | |
---|---|---|---|---|
思想 | 淘汰不再需要或最远将来才会用到的页面 | 淘汰在内存中停留时间最长的页面 | 淘汰最长时间未被使用的页面 | 淘汰内存中使用次数最少的 |
特点 | 理论上最佳,实践中该算法无法实现 | |||
优点 | 实现简单:页面按进入内存的时间排序,淘汰队头页面 | |||
缺点 | 进程只有按顺序访问地址空间时页面命中率才最理想 | |||
异常 | 对于一些特定的访问序列,分配页框越多,缺页率越高 |
页表存在的问题
解决
页目录 | 二级页表10位 | 页框10位 |
---|---|---|
12位 | 10位 | 10位 |
页面划分无逻辑含义;页的共享不灵活;页内碎片
进程分段:把进程按逻辑意义划分为多个段,长度不定。进程由多段组成(代码段、数据段、堆栈段)
段式内存管理系统的内存分配:以段为单位装入,每段分配连续的内存;段和段之间不要求相邻
虚拟地址的种类:段式地址
虚拟地址VA:包含段号S和段内位移W,没有固定长度
段表:记录每段在内存中映射的位置
段号 | 段长 | 段基地址 |
---|---|---|
S | L(W<=L) | B |
段地址映射
段表的扩充
段号 | 段长 | 段基地址 | 中断位 | 访问位 | 修改位 | R | W | X |
---|---|---|---|---|---|---|---|---|
S | L(W<=L) | B |
页共享
段需要连续的存储空间;段的最大尺寸受到内存大小的限制;在辅存中管理可变尺寸的段比较困难
页式 | 段式 | |
---|---|---|
地址 | 一维地址空间 | 二维地址空间 |
长度 | 大小固定 | 可变 |
划分意义 | 无 | 有 |
共享方向性 | 相对不方便 | 相对方便 |
用户可见性 | 不可见 | 可见 |
偏移 | 无溢出 | 有溢出 |
定义:在段式存储管理中结合页式存储管理技术;在段中划分页,内存按页划分,按页装入;
虚拟地址的种类:段页式地址
虚拟地址VA:包含段号S、页号P、页内偏移W
同时采用段表和页表实现地址映射
段页地址映射
特点:内存文件系统;为用户访问内核信息提供接口(CPU,内核信息)
/proc下重要文件与子目录
按交互对象分类
按交互方向分类
输入设备:键盘、扫描仪
输出设备:显示设备、打印机
双向设备:输入/输出:硬盘、软盘、网卡
按外设特性分类
状态跟踪、设备分配、设备映射、设备控制/设备驱动、缓冲区管理
生成设备管理器的数据结构,动态地记录各种设备的状态
设备分配功能是设备管理的基本任务。
设备分配程序按照一定的策略,为申请设备的进程分配设备,记录设备的使用情况
物理设备:I/O系统中实际安装的设备
物理名:ID或字符串
逻辑设备:应用软件使用的设备
逻辑名:友好名(Friendly Name),(\\.\MyDevice, Win), (/dev/Mydevice, Linux)
设备映射:
设备独立性:
设备驱动功能:
对物理设备进行控制,实现I/O操作。
把来自应用的服务请求(例如读/写命令)转换为一系列I/O指令,控制设备完成相关操作。
向用户提供统一的设备使用接口
设备驱动特点:
I/O缓冲区管理的任务:
独占型设备:包括了所有字符型设备
共享型设备:包括了所有块设备
分配方法:独占分配,共享分配,虚拟分配
独占分配:申请成功——开始使用——用完释放
共享分配:即时申请(存储块)即时分配;因为要保证一次I/O操作原子性,有可能阻塞。
虚拟分配:申请独占设备,实际分配虚拟设备
虚拟技术:在一类物理设备上模拟另一类物理设备的技术。通常借助辅存的一部分区域模拟独占设备,将独占设备转化为共享设备。
虚拟设备:用来模拟独占设备的部分辅存称为虚拟设备,虚拟独占设备
输入井:模拟输入设备的辅存区域
输出井:模拟输出设备的辅存区域
虚拟分配:进程申请独占设备,采用虚拟技术将该独占设备虚拟化出来的虚拟设备(部分辅存)分配给它
SPOOLing:虚拟技术和虚拟分配的具体实现方案,外围设备同时联机操作(假脱机输入输出操作)
缓冲:是两种不同速度的设备之间传输信息时平滑传输过程的常用手段
缓冲类别:
作用:对存储设备而言;提高数据传输效率;减少进程访问目标设备的次数;
提前读:进程处理一个输入数据时,直接从I/O缓冲区读入,正确的数据已被提前读入到I/O缓冲区
延后写:进程输出数据时,仅把数据写入I/O缓冲区中。此后,待输出设备空闲时,缓冲区的数据写入输出设备
双缓冲:
环形缓冲:若干缓冲单元首尾链接形成一个环
Loadable Kernel Module: LKM
作用:解决单体内核机制的不足
简单模块程序:
#include
static int hello_init(void)
{
printk("Hello, Kernel!\n"); // 输出到内核信息 dmseg查看
return 0;
}
static void hello_exit()
{
printk("Exit Kernel!\n");
}
module_init(hello_init); // insmod安装时调用, lsmod查看安装结果
module_exit(hello_exit); // rmmod卸载时调用
Linux设备分类
设备文件
驱动程序基本接口
4个面向用户的接口
static int chr_open(struct inode *pinode, struct file *pfile)
{
printk(KERN_EMERG "line:%d, %s is called\n", __LINE__, __FUNCTION__);
return 0;
}
static int chr_read(struct file *pfile, char __user *buff, size_t size, loff_t *off)
{
printk(KERN_EMERG "line:%d, %s is called\n", __LINE__, __FUNCTION__);
return 0;
}
static int chr_write(struct file *pfile, char __user *buff, size_t size, loff_t *off)
{
printk(KERN_EMERG "line:%d, %s is called\n", __LINE__, __FUNCTION__);
return 0;
}
static int chr_release(struct inode *pinode, struct file *pfile)
{
printk(KERN_EMERG "line:%d, %s is called\n", __LINE__, __FUNCTION__);
return 0;
}
file_operations结构体
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*dir_notify)(struct file *filp, unsigned long arg);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
};
具体file_operation定义和初始化
static const struct file_operation chr_fops =
{
.read = chr_read,
.write = chr_write,
.release = chr_release,
.open = chr_open,
};
2个面向IO管理器的接口
static int __init chr_init(void) {
printk(KERN_EMERG "Install chr driver.\n");
alloc_chrdev_region(&dev_no, 0, 1, "chr_demo"); // 动态分配设备号
cdev_init(&chr_dev, &chr_fops); //初始化cdev结构,绑定fops
chr_dev.owner = THIS.MODULE;
cdev_add(&chr_dev, dev_no, 1); //注册设备
dev_class = class_create(THIS_MODULE, "chr_demo");
device_create(dev_class, NULL, dev_no, NULL, "chr_demo"); //创建设备文件
return 0;
}
static int __exit chr_init(void) {
printk(KERN_EMERG "Uninstall chr driver.\n");
device_destroy(dev_class, dev_no);
class_destroy(dev_class);
cdev_del(&chr_dev); //注销设备
unregister_chrdev_region(dev_no, 1); //释放占用的设备号
}
module_init(chr_init);
module_exit(chr_exit);
Makefile
obj-m := chr_driver.o
KDIR := /lib/modules/`uname -r`/build
PWD := $(shell pwd)
default:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -rf *.o *.mod.* *.ko *.symvers *.order
测试
驱动程序模块插入内核
insmod chr_driver.ko
查看是否载入
cat /proc/devices
从内核移除设备
rmmod chr_driver
测试程序
int main(void)
{
int fd;
char buf = 0x01;
fd = open("/dev/chr_demo", O_RDWR); // 打开设备文件
printf("%d\n", fd);
read(fd, &buf, 1); // 读
write(fd, &buf, 1); // 写
close(fd);
return 0;
}
文件定义:文件是系统中信息存放的一种组织形式
文件分类:
文件属性
文件系统:
逻辑结构:
物理结构:
记录式文件:
流式文件:现代OS中文件是流式,由应用解释文件(比如pdf阅读器打开pdf文件)
文件的存取:
顺序存取:按文件信息单位排列的顺序依次存取
随机存取:直接存取,每次存取操作时先确定存取位置
文件读写示例
FILE *pFile = fopen("demo.txt", "rb");
char *pBuf;
fseek(pFile, 0, SEEK_END); // 移动文件指针到末尾
int len = ftell(pFile); // 获取文件指针偏移量
pBuf = new char[len];
rewind(pFile); // 指针移动到文件头
fread(pBuf, 1, len, pFile); // 读
fclose(pFile);
连续文件
串联文件:文件信息存放在不连续的存储块中(FAT文件系统)
索引文件:文件存放在不连续的物理块中,系统建立索引表记录文件的逻辑块和存储块的对应关系
定义:记录当前磁盘的使用情况,创建文件时分配存储空间,删除文件时收回存储空间
空闲文件:一片连续空闲区当作一个特殊文件,该文件由多个连续的空闲存储块组成。所有的空闲文件代表存储设备的空闲空间
记录磁盘空闲块的方法:空闲文件目录,空闲块链、位示图
空闲文件目录:记录所有空闲文件,每个表项对应一个空闲文件
空闲块链:把存储设备上的所有空闲块链接在一起
位示图:从内存中划出若干个字节,每位对应1个存储块
文件目录:文件名址录,记录文件名和存放地址的目录表
为了对大量文件进行分门别类的管理,提高文件检索的效率,现代操作系统往往将文件的一些属性也记录在目录中
目录文件:文件目录以文件形式存于外存,这个文件叫目录文件
文件目录的功能:将文件名转换为外存物理位置的功能
文件全名和路径:包括从根目录开始到文件为止的通路上所有子目录路径
Linux的目录是树形结构
文件的保护
文件操作
目录操作
创建目录
目标:让用户以文件名来存取文件
逻辑结构:
物理结构:
记录式文件:
流式文件:现代OS中文件是流式,由应用解释文件(比如pdf阅读器打开pdf文件)
文件的存取:
顺序存取:按文件信息单位排列的顺序依次存取
随机存取:直接存取,每次存取操作时先确定存取位置
文件读写示例
FILE *pFile = fopen("demo.txt", "rb");
char *pBuf;
fseek(pFile, 0, SEEK_END); // 移动文件指针到末尾
int len = ftell(pFile); // 获取文件指针偏移量
pBuf = new char[len];
rewind(pFile); // 指针移动到文件头
fread(pBuf, 1, len, pFile); // 读
fclose(pFile);
连续文件
[外链图片转存中…(img-B0pSobgd-1641814982957)]
串联文件:文件信息存放在不连续的存储块中(FAT文件系统)
[外链图片转存中…(img-E834Y4YH-1641814982958)]
索引文件:文件存放在不连续的物理块中,系统建立索引表记录文件的逻辑块和存储块的对应关系
[外链图片转存中…(img-euIsRz9K-1641814982959)]
定义:记录当前磁盘的使用情况,创建文件时分配存储空间,删除文件时收回存储空间
空闲文件:一片连续空闲区当作一个特殊文件,该文件由多个连续的空闲存储块组成。所有的空闲文件代表存储设备的空闲空间
记录磁盘空闲块的方法:空闲文件目录,空闲块链、位示图
空闲文件目录:记录所有空闲文件,每个表项对应一个空闲文件
[外链图片转存中…(img-GDWPsEWC-1641814982959)]
空闲块链:把存储设备上的所有空闲块链接在一起
位示图:从内存中划出若干个字节,每位对应1个存储块
[外链图片转存中…(img-V84ZHY5i-1641814982959)]
文件目录:文件名址录,记录文件名和存放地址的目录表
为了对大量文件进行分门别类的管理,提高文件检索的效率,现代操作系统往往将文件的一些属性也记录在目录中
目录文件:文件目录以文件形式存于外存,这个文件叫目录文件
文件目录的功能:将文件名转换为外存物理位置的功能
文件全名和路径:包括从根目录开始到文件为止的通路上所有子目录路径
Linux的目录是树形结构
文件的保护
文件操作
目录操作