主要是把在重读 《现代操做系统》 中以为有价值的东西,以 Tips 的形式记录下来。不可能面面俱到,可是若是有必定的基础应该是会回想起不少知识的。具体解释将会以连接形式补充。GitHub
相关阅读 : 重拾数据结构node
主要是为了支持伪并发能力git
CPU 利用率 = 1 - p ^ n
p : IO 等待时间比
n : 进程数github
每个进程有一个地址空间和一个控制线程,主要是使某个进程内的任务之间不被相互阻塞,实现一种进程内并行操做的假象。建立销毁更加轻量级。算法
共享一组资源,协同完成任务。每一个线程有本身的堆栈区(由于要区分同一进程内的线程,CPU 调度要进行状态的保存)编程
两个或者多个进程读写某些共享数据缓存
将共享内存的访问代码称为临界区,确保在每一个时刻两个进程不可能同时处于临界区中,这样能够避免竞争条件。核心思想为互斥。安全
并发程序准确高效要知足一下四个条件数据结构
互斥实现方案并发
每一个进程进入临界区后当即屏蔽全部中断,这样 CPU 没法进行进程切换,就要离开临界区是打开中断。函数
设置一个共享锁变量,初始值为 0。当一个进程想要进入临界区,必须检测锁的值是否为 0,是则置 1 进入临界区。不是则等待其余进程退出临界区时释放锁直到本身能获取到锁开始进入临界区。
锁变量仍是会产生竞争条件
一直循环等待直到出现容许该进程进入临界区的条件才开始运行,十分消耗 CPU 资源。
避免了竞争条件,可是临界区外运行的程序会发生阻塞
用于忙等待的锁称为自旋锁。
A:
while (TRUE) {
while (turn != 0);
critical_region();
turn = 1;
noncritical_region();
}
B:
while (TRUE) {
while (turn != 1);
critical_region();
turn = 0;
noncritical_region();
}复制代码
一种互斥算法
#define FALSE 0
#define TRUE 1
#define N 2
int turn;
int interested[N];
void enter_region(int process) {
int other;
other = 1 - process;
interested[process] = TRUE;
turn = process;
// 若是有另外一个程序进入临界区的话则一直空循环
while (turn == process && interested[other] == TRUE);
}
void leave_region(int process) {
interested[process] = FALSE;
}复制代码
前面的弊端是忙等待会消耗 CPU 资源。若是在等待进入临界区时能够挂起,等到某个信号到达再唤醒就能够避免这种状况了。
利用资源缓冲区实现进程间的协调
#define N 100
int count = 0;
void producer(void) {
int item;
while (TURE) {
item = produce_item();
if (count == N) {
sleep();
}
insert_item(item);
count = count + 1;
if (count == 1) {
wakeup(consumer);
}
}
}
void consumer(void) {
int item;
while (TURE) {
if (count == 0) {
sleep();
}
item = remove_item();
count = count - 1;
if (count == N - 1) {
wakeup(producer);
}
consume_item(item);
}
}复制代码
引入一个信号量来累计唤醒次数,能够为 0 或正数
使用 down 和 up 操做代替 sleep 和 wakeup
#define N 100
typedef int semaphore
semaphore mutex = 1; // 控制对临界区的访问
semaphore empty = N; // 计数缓冲区的空槽数目
semaphore full = 0; // 计数缓冲区的满槽数目
void producer(void) {
int item;
while (TRUE) {
utem = produce_item();
down(&empty);
down(&mutex);
insert_item(item);
up(&mutex);
up(&full);
}
}
void consumer(void) {
int item;
while (TRUE) {
down(&full);
down(&mutex);
item = remove_item();
up(&mutex);
up(&empty);
consume_item(item);
}
}复制代码
仅仅适用于管理共享资源或一小段代码
当有多个进程处于就绪态时就面临调度的选择。
内核管理线程时调度能够认为是线程级别的。
进程行为有计算密集型
和I/O 密集型
。而如今因为 CPU 改进速度加快,进程行为更倾向于后者,因此应该多运行该类进程保持 CPU 的利用率。
批处理
交互式
aT0 + (1 - a)T1
)实时
线程调度
和系统支持的线程实现方式有关(理解 : 线程表存在哪的区别)
用户级线程 : 内核并不知道,内核只是选中该进程,至于进程中跑哪一个线程由用户态调度决定。
内核级线程 : 直接调度某个进程内的线程。
以上两种方式在性能上有主要差异 : 前面说起 I/O 操做实际上是很耗时的,因此在进程间切换比在线程间切换更加耗时。由于线程轻量,而进程完成切换要完整的山下文切换,修改内存映像。并且同一进程内的线程 I/O 访问 cache 的局部性更高,不一样进程间切换的清理缓存,这也会消耗时间。
主要思想就是内存抽象
程序产生的地址为虚拟地址,在没有虚拟内存的操做系统上,直接将地址输送到内存总线上。而有虚拟内存的操做系统上,把虚拟地址输送到 MMU(Memory Management Unit),由 MMU 将虚拟地址映射为为物理地址。
虚拟地址空间 : 页面 物理内存地址 : 叶框 4k大小
虚拟地址 = 虚拟页号(高位) + 偏移量(低位)
页表 : 把虚拟地址的页面映射为页框,每一个进程都有本身的页表
加速分页方法 : 转换检测缓冲区(TLB)主要是优先在 TLB 中查找页面号。
大内存页表
最优页面置换算法不可实现,由于没法肯定将来。
设置访问(读、写)位 R,页面修改位 M。
设置一个检测最老页面位 R
链表实现页面选择
利用矩阵模拟 : 增长自身权重减小其余权重,行置 1,列置 0。
老化算法
算法 | 注释 |
---|---|
最优算法 | 不可实现,但可做为基准 |
NRU(最近未使用)算法 | LRU 的很粗糙近似 |
FIFO(先进先出)算法 | 可能抛弃重要页面 |
第二次机会算法 | 比 FIFO 有大的改善 |
时钟算法 | 现实的 |
LRU(最近最少使用)算法 | 很优秀,但很难实现 |
NFU(最不常用)算法 | LRU 的相对粗略的近似 |
老化算法 | 很是近似 LRU 的有效算法 |
工做集算法 | 实现起来开销很大 |
工做集时钟算法 | 好的有效算法 |
进程发起系统调用,把文件映射到其虚拟地址空间的一部分。通常实现是开始不加载,在程序访问时在按页加载。
// Linux 待填
段是逻辑实体,大小不固定。
还有 Intel Pentuium 未介绍
34 位的 MULTICS 虚拟地址
段号 | 页号 | 页内偏移 |
---|---|---|
18 | 6 | 10 |
文件系统存放在磁盘上。多数磁盘划分为一个或多个分区,每一个分区中有一个独立的文件系统。磁盘的 0 号盘扇区称为主引导记录(Master Boot Record, MBR),用来引导计算机。在 MBR 的结尾是分区表,该表给出了每一个分区的其实和结束地址。表中的一个分区被标记为活动分区。在计算机被引导时,BIOS 读入并执行 MBR。MBR 作的第一件事是肯定活动分区,读入它的第一个块,称为引导块,并执行。
整个分区:
MBR | 分区表 | 磁盘分区 | 磁盘分区 | 磁盘分区... |
---|---|---|---|---|
磁盘分区:
引导块 | 超级块 | 空闲空间管理 | i 节点 | 根目录 | 文件和目录 |
---|---|---|---|---|---|
把每一个文件做为一连串连续数据块存储在磁盘上。
一个文件由几个磁盘块组成。
把每一个磁盘块的指针字放在内存的一个表中
每一个文件赋予一个称为 i 节点(index-node)的数据结构,列出文件属性和文件快的磁盘地址。
块设备 : 以块为单位传输,可寻址
字符设备 : 以字符为单位收发字符流,不可寻址
DMA 工做原理:
在进程对设备,文件等取得了排他性访问权限的时候,有可能会出现死锁。这类须要排他性使用的对象称为资源。
能够从拥有它的进程中抢占而不会产生任何反作用。(存储器)
指在不引发相关的计算失败的状况下,没法把他从占有它的进程处抢占过来。( CD 刻录)
资源使用步骤:
若是一个进程集合中的每一个进程都在等待只能由该进程集合中的其余进程才能引起的事件,那么,该进程集合就是死锁的。
发生资源死锁的四个必要条件:
死锁检测主要是判断当前空闲资源在某种合理分配下是否能使全部进程都运行完而且最终资源都可以释放。
恢复方法 :
死锁避免从本质上来讲是不可能的,由于他要获取将来的信息。
若是资源不被一个进程独占死锁不会发生。(假脱机打印机)
开始执行前请求全部资源就不会形成等待。另外一种是请求资源时先释放本身所持有的资源,再尝试一次请求资源。
针对某些资源进行虚拟化,实现可抢占。
保证每一个进程在任什么时候刻只能占用一个资源若是要请求另一个资源它必须先释放第一个资源。另外一种是将全部资源统一编号,进程能够在任什么时候刻提出资源请求,可是请求必须按照资源编号顺序(升序)提出。