完全图:完全图就是能连的边都连起来的图
在有向图中,若从顶点v到顶点w和从顶点w到顶点v之间都有路径,则这两个顶点是强连通的
若有向图中任何顶点都是强连通的,那么这个图就是强连通图
邻接表:
#define MaxVertexNum 100
//边表结点结构体
typedef struct ArcNode
{
int adjex;//该弧指向的顶点的位置
struct ArcNode *next;//指向下一条弧的指针
}ArcNode;
//定义顶点结构体
typedef struct VNode
{
VertexType data;
ArcNode *first;//指向第一个依附于该顶点的弧的指针
}VNode;
//广度优先搜索遍历
//广度优先搜索是一个分层的查找,每向前走一步可能访问一批顶点,不是一个递归算法。为了实现逐层的访问,算法必须借助一个辅助队列,以记忆正在访问的顶点的下一层顶点
bool visited[Max_Vertex_Num];//访问标记数组
void BFSTraverse(Graph G)
{
for(int i=0;i=0;w=NextNeighbor(G,v,w))
{
//检测v的所有邻接点
if(!visited[w])
{
visit(w);
visited[w]=true;
EnQueue(Q,w);
}//if
}//for
}//while
}
/*BFS的算法复杂度:
空间复杂度:O(|V|)
时间复杂度:
邻接表:O(|V|+|E|)
邻接矩阵:O(|V|^2)
*/
//从顶点出发,对图进行广度优先遍历
int visited[Size];//定义辅助数组,标记顶点是否被访问过
Queue Q;//定义辅助队列
void BFSTraverse(Graph G)
{
InitQueue(Q);
//初始化标记数组
for(int i=0;i=0;w=NextNeighbor(G,v,w))
{
//检测顶点是否被访问过
if(!visited[w])
{
visit(w);
visited[w]=true;
EnQueue(Q,w);
}
}
}
}
//BFS求解单源最短路径问题
void BFS_Min_Distance(Graph G,int u)
{
int *distance=new int[Size];//申请一个数组存放,访问的距离
int *path=new int[Size];//
//d[i]表示从u到i结点的最短路径
for(int i=0;i=0;w=NextNeighbor(G,w,v))
{
if(!visited[v])
{
DFS(G,w);
}
}
}
B树的高度:
logm(n+1)<=h<=logm((n+1)/2 +1)
红黑树的性质:
核心态:也叫做管态
用户态:也叫做目态
用户态转向和心态的例子:
中断的分类:
| 调用类型 | 中断 | 子程序调用 |
|---|---|---|
| 入口地址 | 由中断隐指令根据中断向量得到 | 由调用程序根据寻址方式得到 |
| 保护环境 | 保存PC,PSW,通用寄存器 | 保存PC,通用寄存器 |
| 进程状态 | 从用户态转换为核心态 | 没有发生变化 |
| 有中断请求时,先由中断隐指令完成中断前程序状态保存,主要工作有: |
对于支持多重中断的OS来说步骤如下:
什么时候需要系统调用?
如果一个操作可能会影响到其他进程,那么就需要借助OS来完成,此时需要系统调用
系统调用的过程:
命题重点:
进程通信:
将n个用户级线程映射到m个内核级线程上。
操作系统只能"看见"内核级线程,因此只有内核级线程才是处理机分配的单位。
例如:一个进程又两个内核级线程,三个用户级线程,在用户看来,这个进程有三个进程。但即使该进程在一个4核处理机的计算机上运行,也最多只能被分配到两个核,最多只能有两个用户级线程并行执行。
在多处理机系统中,内核能够同时调度同一进程中多个线程并行执行
引发进程创建的事件:
创建进程的步骤:
引发进程终止的事件:
引发进程阻塞的事件:
引发进程唤醒的事件:
周转时间:做完完成时间-作业提交时间
带权周转时间=作业周转时间/作业实际运行时间
注意:区分作业的周转时间和进程的周转时间不一样。
进程调度的优先级:
不能进程处理机调度的情况:
调度算法
互斥访问的原则:
单标志法:违背空闲让进
双标志前检查法:违背忙则等待
双标志后检查法:违背空闲让进,忙则等待
Peterson:不满足让权等待
记录型信号量:
semaphore mutex=1;//互斥访问缓冲区
semaphore free=n;//表示缓冲区中空位数量
smephore message=0;//表示缓冲区中的消息数量
Producer()
{
while(true)
{
p(free);
Message msg=Produce();//生产一个消息
p(mutex);
PuMsg(msg);//放到缓冲区
v(mutex);
V(message);
}
}
Comsumer()
{
while(true)
{
p(message);
p(mutex);
GetMessage();
v(mutex);
V(free);
}
}
//爸爸向盘子放苹果,妈妈向盘子放橘子,儿子吃橘子,女儿吃苹果
semaphore panzi=1;//盘子的数量
semaphore mutex=1;//爸爸妈妈互斥访问盘子
semaphore pingguo=0;//表示盘子中的苹果数量
semaphore juzi=0;//表示盘子中橘子的数量
Dad()
{
while(true)
{
p(panzi);
p(mutex);
Putapple();
v(mutex);
}
}
Mum()
{
while(true)
{
p(panzi);
p(mutex);
PutOrange();
v(mutex);
}
}
Son()
{
while(true)
{
p(juzi);
p(mutex);
EatOrange();
v(mutex);
V(panzi);
}
}
Daughter()
{
while(true)
{
p(juzi);
p(mutex);
EatApple();
v(mutex);
V(panzi);
}
}
/*
1.允许多个读者可以同时对文件执行读操作
2.只允许一个写者进程往文件中写操作
3.任一写者在完成操作之间不允许读者进程进行读
*/
int count=0;//用于距离当前读者进程的数量
semaaphore mutex=1;//互斥访问count变量
semahore writer=1;//用于保证读者和写者互斥访问文件
Writer()
{
while(true)
{
p(rw);
writing();
v(rw);
}
}
//第一个读者和最后一个读者需要操作rw,其他的读者只需要更改count即可
Reader()
{
p(mutex);
if(count==0)
{
p(rw);
count++;
}else{
count++;
}
v(mutex);
read();
p(mutex);
count--;
if(mutex==0)
{
v(rw);
}
v(mutex);
}
//上面的代码可能会导致写者进程出现饥饿现象,进行下面的这种修正
int count=0;
semahore mutex=1;
semaphore rw=1;
semaphore writer=1;//用于同步在读者进程在访问卡住后面来的读者进程
Writer()
{
while(true)
{
p(writer);
p(rw);
p(mutex);
writing();
v(mutex);
v(writer);
}
}
Reader()
{
while(true)
{
p(writer);//在无写者进程时进入
p(mutex);
if(count==0)
{
p(rw);
}
count++;
v(mutex);
v(writer);
read();
p(mutex);
count--;
if(mutex==0)
{
v(rw);
}
v(mutex);
}
}
//哲学家进餐问题
//为了防止发生死锁,做出这样的限制,当一名哲学家左右两边的筷子都可用时,才允许它抓起快读吃饭
semaphore chopstick[5]={1,1,1,1,1};
semaphore mutex=1;
Process_i()
{
while(true)
{
p(mutex);
p(chopstick[i]);//左边的筷子可用
p(chopstick[(i+1)%5];//右边的筷子可用
v(mutex);
eat();
V(chopstick[i]);
V(chopstick[(i+1)%5]);
}
}
//吸烟者问题
int num=0;//存储随机数
semaphore offer1=0;//烟草和纸的组合
semaphore offer2=0;//烟草和胶水组合
semaphore offer3=0;//烟草和胶水的组合
semaphore finish=0;//表示抽烟是否结束
Process P1()
{
while(1)
{
num++;
num=num%3;
if(num==0)
{
v(offer1);
}else if(num==1)
{
v(offer2);
}else if(num==2)
{
v(offer3);
}
p(finish);
}
}
Process P2()
{
while(true)
{
P(offer1);
v(finish);
}
}
Process P3()
{
while(true)
{
P(offer2);
v(finish);
}
}
Process P4()
{
while(true)
{
P(offer3);
v(finish);
}
}
读者——写者问题
哲学家进餐问题
死锁条件:
预防死锁
避免死锁
死锁检测和接触
资源分配图
硬件支持:页表寄存器(PTR),存放页表在内存的始地址和页表长度
页表的开始地址和页表长度平时是存放在进程的PCB中的,只有进程上处理机运行时才会放在寄存器中。
缺页中断的处理过程:
缺页中断的目的是要将位于外存上的代码或数据装入内存,此时应将缺页的进程阻塞,如果内存中由空闲的也,则分配一块,将要调入的页装入该块,并修改页表中相应的页表项,此时若内存中没有空闲块,则需亚奥淘汰一个页。
缺页中断作为中断页同样要经历,诸如CPU环境,分析中断原因,转入缺页中断处理程序,恢复CPU环境等几个步骤。但与一般的中断相比,它有以下几个明显的区别:
文件管理的命题重点:
一个FCB就是一个目录项,FCB和目录的目的是为了实现"按名存取"
操作系统维护一个打开文件表(open-file table),当需要一个文件操作时,可以通过该表的一个索引指定文件,就省略了搜索环节。
如果调用open的请求得到允许,进程就可以打开文件,而open通常返回一个指向打开文件表中的一个条目的指针。通过使用该指针(而非文件名)进行IO操作,以简化步骤并节省资源
文件分配:
命题重点:
中断处理层的主要工作有:进行进程的上下文切换,对处理中断信号源进行测试,读取设备状态和修改进程状态等
引入控制器后,系统可以通过几个简单的参数完成对控制器的操作,而具体的硬件操作则由控制器调用相应的设备接口完成,使CPU从繁重的设备控制操作中解放出来
单缓冲:Max(C,T)+M
双缓冲区:Max(C+M,T)