1.进程和线程以及其区别?
(1)进程是系统资源分配的最小单元,可实现操作系统的并发,也就是同一段时间内可以有多个进程同时运行,而线程是cpu调度的最小单元,它可以实现进程内部并发。
(2)进程是一个独立的单元,而线程必须依托进程才能存在,一个进程中至少包含一个线程。
(3)线程自己除了栈和程序计数器是自己私有的外基本上不拥有独立的系统资源。(栈和程序计数器用来保存线程的执行历史和线程的执行状态,是线程私有的资源。),它所用的资源都派生于它的进程中的资源。且所有线程共享这块资源。
(4)线程间切换的开销远 小于进程。
2.几种常见的操作系统调度策略
一.先来先服务和短作业(进程)优先调度算法
1.先来先服务调度算法
先来先服务采用队列的一种方式最先到的,将它们调入内存,为它们分配资源、创建进程,然后放入就绪队列。
2.短作业(进程)优先调度算法
从后备队列中选择一个或若干个估计运行时间最短的作业,将它们调入内存运行。不足:主要的不足之处是长作业的运行得不到保证
二.高优先权优先调度算法‘
1.优先权调度算法的类型
非抢占式:在这种方式下,系统一旦把处理机分配给就绪队列中优先权最高的进程后,该进程便一直执行下去,直至完成
抢占式:在这种方式下,系统同样是把处理机分配给优先权最高的进程,使之执行。但在其执行期间,只要又出现了另一个其优先权更高的进程,进程调度程序就立即停止当前进程(原优先权最高的进程)的执行,重新将处理机分配给新到的优先权最高的进程
2.高响应比优先调度算法
Rp越大优先级越大。
(1)如果作业的等待时间相同,则要求服务的时间愈短,其优先权愈高,因而该算法有利于短作业。
(2)当要求服务的时间相同时,作业的优先权决定于其等待时间,等待时间愈长,其优先权愈高,因而它实现的是先来先服务。
(3) 对于长作业,作业的优先级可以随等待时间的增加而提高,当其等待时间足够长时,其优先级便可升到很高,从而也可获得处理机。
当然,在利用该算法时,每要进行调度之前,都须先做响应比的计算,这会增加系统开销。
三.基于时间片的轮转调度算法
1.时间片轮转法
就是给对列中的每个队首位置的进程让他执行一段时间,如果在这段时间内执行完或者阻塞,则CPU当即进行切换给下个进程用,如果没有执行完,则CPU也会将被剥夺并分配给下一个进程
时间片设得太短会导致过多的进程切换,降低了CPU效率;而设得太长又可能引起对短的交互请求的响应变差。
2.多级反馈队列调度算法
前面介绍的各种用作进程调度的算法都有一定的局限性。如短进程优先的调度算法,仅照顾了短进程而忽略了长进程,而且如果并未指明进程的长度,则短进程优先和基于进程长度的抢占式调度算法都将无法使用。而多级反馈队列调度算法则不必事先知道各种进程所需的执行时间,而且还可以满足各种类型进程的需要
多 级反馈队列调度算法可以说是最好的一种算法,UNIX操作系统采取的便是这种调度算法。多队列调度是根据进程的性质和类型的不同,将就绪队列再分为若干个子队列,所有的进程按其性质排入相应的队列中,而不同的就绪队列采用不同的调度算法。
3.什么是死锁?死锁产生的条件?
指多个进程因竞争共享资源而造成的一种僵局,若无外力作用,这些进程都将永远不能再 向前推进。
死锁产生的四个条件(有一个条件不成立,则不会产生死锁)
互斥条件:一个资源一次只能被一个进程使用
请求与保持条件:一个进程因请求资源而阻塞时,对已获得资源保持不放
不剥夺条件:进程获得的资源,在未完全使用完之前,不能强行剥夺
循环等待条件:若干进程之间形成一种头尾相接的环形等待资源关系
4.什么是银行家算法?
银行家算法(Banker’s Algorithm)是一个避免死锁(Deadlock)的著名算法,是由艾兹格·迪杰斯特拉在1965年为T.H.E系统设计的一种避免死锁产生的算法。它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行。
在银行中,客户申请贷款的数量是有限的,每个客户在第一次申请贷款时要声明完成该项目所需的最大资金量,在满足所有贷款要求时,客户应及时归还。银行家在客户申请的贷款数量不超过自己拥有的最大值时,都应尽量满足客户的需要。在这样的描述中,银行家就好比操作系统,资金就是资源,客户就相当于要申请资源的进程。
银行家算法是一种最有代表性的避免死锁的算法。在避免死锁方法中允许进程动态地申请资源,但系统在进行资源分配之前,应先计算此次分配资源的安全性,若分配不会导致系统进入不安全状态,则分配,否则等待。为实现银行家算法,系统必须设置若干数据结构。
银行家算法中的数据结构
银行家算法中的数据结构
为了实现银行家算法,在系统中必须设置这样四个数据结构,分别用来描述系统中可利用的资源、所有进程对资源的最大需求、系统中的资源分配,以及所有进程还需要多少资源的情况。
(1) 可利用资源向量 Available。这是一个含有 m 个元素的数组,其中的每一个元素代表一类可利用的资源数目,其初始值是系统中所配置的该类全部可用资源的数目,其数值随该类资源的分配和回收而动态地改变。如果 Available[j] = K,则表示系统中现Rj类资源K个。
(2) 最大需求矩阵Max。这是一个n x m的矩阵,它定义了系统中n个进程中的每个进程对m类资源的最大需求。如果Max[i,j] = K,则表示进程i需要Rj 类资源的最大数目为K。
(3) 分配矩阵 Allocation。这也是一个n x m的矩阵,它定义了系统中每一类资源当前已分配给每一进程的资源数。如果 Allocation[i,jl = K,则表示进程i当前己分得Rj类资源的数目为K。
(4) 需求矩阵Need.这也是一个n×m的矩阵,用以表示每一个进程尚需的各类资源数。如果Need[i,j] = K,则表示进程i还需要Rj类资源K个方能完成其任务。
上述三个矩阵间存在下述关系:
Need[i,j] = Max[i,j] - allocation[i, j]
银行家算法详述:
设 Request;是进程Pi的请求向量,如果 Requesti[j] = K,表示进程Pi需要K个Rj类型的资源。当Pi发出资源请求后,系统按下述步骤进行检査:
(1) 如果 Requesti[j] ≤ Need[i,j]便转向步骤(2);否则认为出错,因为它所需要的资源数已超过它所宣布的最大值。
(2) 如果 Requesti[j] ≤ Available[j],便转向步骤(3);否则,表示尚无足够资源,Pi须等待。
(3) 系统试探着把资源分配给进程Pi,并修改下面数据结构中的数值
Available[i] = Available[j] - Requesti[j];
Allocation[i,j] = Allocation[i,j] + Requesti[j];
Need[i,j] = Need[i,j] - Requesti[j];
(4) 系统执行安全性算法,检查此次资源分配后系统是否处于安全状态。若安全,才正式将资源分配给进程Pi,以完成本次分配;否则,将本次的试探分配作废,恢复原来的资源分配状态,让进程Pi等待。
现在我们来对上面算法,来模拟一个银行贷款的一个流程
分别定义 A B C D 4 种数据结构 ,分别代表上文的Available(A),Max(B),Allocation(C),Need(D),A的含义代表银行剩余资金,B代表它的信用额度 C代表当前已贷款金额,D代表还需多少金额。假设 A =4000 B = 3000 C=0 D =0
好了目前有一个用户user(进程Requesti),我们简称u,他想贷款3000元,流程就是 首先银行查看它的信用额度是否满足条件为3000满足 , u<=B( Requesti[j] ≤ Need[i,j])进行下一步,银行查看自己是否能借出3000元发现 u<=A( Requesti[j] ≤ Available[j]) 也满足条件,执行贷款操作,首先将银行帐上的钱扣除3000 A=A-u( Available[i] = Available[j] - Requesti[j];)然后将用户的已贷款金额加3000 C=C+u(Allocation[i,j] = Allocation[i,j] + Requesti[j]),然后将其还需贷款金额减去请求的金额D=D-u(Need[i,j] = Need[i,j] - Requesti[j])
5.哲学家就餐问题:
假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。餐桌中间有一大碗意大利面,每两个哲学家之间有一根筷子。因为用一只筷子很难吃到意大利面,所以假设哲学家必须用两只筷子吃东西。他们只能使用自己左右手边的那两只筷子。如下图所示:
哲学家必须用两只筷子吃东西,而且他们只能使用自己左右手边的那两只筷子
有一种情况是会产生死锁的:每个哲学家都拿起了左边的筷子,并在等待右边的筷子。因为右边的筷子正在右侧哲学家的手中,右侧哲学家也在等待更右边的哲学家放下筷子,大家互相持有他人等待的资源并等待着他人释放,导致大家都得不到资源从而出于饥饿状态,这就是造成了死锁。
解决思路:
1.添加一个服务生,只有经过服务生允许后哲学家才能拿叉子,由服务生负责避免死锁。
2.哲学家必须确定左右两边的叉子都可用后,才能同时拿起左右两边的叉子。
3.换手策略,假设1到4位哲学家都从左往右拿筷子,而最后一位哲学家相反。
java实现换手策略:
public class ZheXueJiaEating {
private static class ZheXueJia implements Runnable{
private Object leftChopsticks = null;
private Object rightChopsticks = null;
public ZheXueJia(Object leftChopsticks, Object rightChopsticks) {
this.leftChopsticks = leftChopsticks;
this.rightChopsticks = rightChopsticks;
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true) {
doAction("思考中");
synchronized (leftChopsticks) {
doAction("拿到左边的筷子");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (rightChopsticks) {
doAction("拿到右边的筷子");
doAction("开始进食");
}
}
}
}
private void doAction(String str) {
System.out.println(Thread.currentThread().getName()+":"+str);
try {
Thread.sleep((long) (Math.random()*10));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
//5为哲学家
ZheXueJia[] zheXueJias = new ZheXueJia[5];
//5根筷子
Object[] chopsticks = new Object[zheXueJias.length];
for (int i = 0; i < chopsticks.length; i++) {
chopsticks[i] = new Object();
}
for (int i = 0; i < zheXueJias.length; i++) {
Object leftChopsticks = chopsticks[i];
Object rightChopsticks = chopsticks[(i+1)%chopsticks.length];
ZheXueJia zheXueJias1 = null;
//最后一位哲学家先拿左边的筷子,如果没有拿到就等待,这样不会发生死锁了
if(i == zheXueJias.length - 1) {
zheXueJias1 = new ZheXueJia(rightChopsticks, rightChopsticks);
}else {
zheXueJias1 = new ZheXueJia(rightChopsticks, leftChopsticks);
}
new Thread(zheXueJias1,"哲学家"+(i+1)+"号").start();
}
}
}
以上就是我觉得比较常考的计算机操作系统面试题