本文将介绍操作系统常见的几种算法并给出实现方法,系统架构图如下:
如需源码请参见文章末尾链接
进程管理
1.生产者消费者与读者写者
生产者消费者问题其主要实现就是模拟进程之间的同步与互斥,首先需要设置3个令牌(信号量),即:Empty、Full、mutex(互斥)。
生产者首先需判断获取空的缓冲池,判断是否有空间生产(Empty.acquire());有空间后紧接着就是获取互斥信号量mutex,当获取到mutex就能对临界区进行修改,完成相应的生产任务,记录型信号量增加(即生产,count++)。在随即等待一段时间后(现代计算机CUP处理速度较快,wait是为了能使我们能够看清流程)退出剩余区,即mutex.release()。最后增加一个Full空间(Full..release())。
消费者与之类似,其不同点仅在于其进入临界区消费与退出时的判断逻辑为:是否有空间(产品)消费和增加一个Empty空间(Empty.release())。
常见的进程调度在java中一般使用令牌+进程锁+LinkedList实现基本同步互斥问题,生产者消费者实现核心代码如下:
try
{
synchronized(this){
Random random = new Random();
wait(random.nextInt(500));
ProderAndConsumer.insert3("生产者"+num+"打算生产");
ProderAndConsumer.Pro.add(num+"打算生产");
ProderAndConsumer.Empty.acquire();
ProderAndConsumer.mutex.acquire();
ProderAndConsumer.insert2("生产者"+num+"正在生产");
ProderAndConsumer.Pro.remove(num+"打算生产");
ProderAndConsumer.ing.add("生产者"+num+"正在生产");
wait(random.nextInt(10000)+3000);
ProderAndConsumer.count++;
ProderAndConsumer.insert2("生产者"+num+"结束生产");
ProderAndConsumer.insert3("生产者"+num+"完成生产");
ProderAndConsumer.ing.remove("生产者"+num+"正在生产");
wait(3000);
ProderAndConsumer.fresh.acquire();
ProderAndConsumer.refresh();//刷新页面,通过队列的信息刷新页面
ProderAndConsumer.fresh.release();
ProderAndConsumer.mutex.release();
ProderAndConsumer.Full.release();
}
} catch (InterruptedException e) {
System.out.println("生产者"+num+"出现错误!");
e.printStackTrace();
}
try {
synchronized(this) {
Random random = new Random();
wait(random.nextInt(400));
ProderAndConsumer.insert1("消费者"+num+"打算消费");
ProderAndConsumer.Con.add(num+"打算消费");
ProderAndConsumer.Full.acquire();
ProderAndConsumer.mutex.acquire();
ProderAndConsumer.insert2("消费者"+num+"正在消费");
ProderAndConsumer.Con.remove(num+"打算消费");
ProderAndConsumer.ing.add("消费者"+num+"正在消费");
wait(random.nextInt(5000)+1500);
ProderAndConsumer.count--;
ProderAndConsumer.insert2("消费者"+num+"结束消费");
ProderAndConsumer.ing.remove("消费者"+num+"正在消费");
ProderAndConsumer.insert1("消费者"+num+"完成消费");
wait(3000);
ProderAndConsumer.fresh.acquire(); //实现刷新页面时,线程的互斥
ProderAndConsumer.refresh(); //刷新页面,通过队列的信息刷新页面
ProderAndConsumer.fresh.release();
ProderAndConsumer.mutex.release();
ProderAndConsumer.Empty.release();
}
} catch (InterruptedException e) {
System.out.println("消费者"+num+"出现错误!");
e.printStackTrace();
}
读者写者问题是在生产者消费者问题的基础上改进而来,其不同点仅在于加入一个计数变量count来记录处于读写空间中读者的数量,实现读者可同时读文件,其核心代码如下:
try {
synchronized(this)
{
Random random = new Random();
wait(random.nextInt(500));
ReadAndWrite.insert1("读者"+num+"打算读文件");
ReadAndWrite.Re.add(num+"打算读文件");
ReadAndWrite.w.acquire(); //实现写优先
ReadAndWrite.mutex.acquire(); //防止读者之间同步访问count,读者互斥访问count
if(ReadAndWrite.count==0)
ReadAndWrite.rw.acquire(); //实现读写互斥
ReadAndWrite.count++; //我只要有东西正在读你,你就不许给我写东西,实现多读者同步的关键
ReadAndWrite.mutex.release();
ReadAndWrite.w.release();
//以下为读文件的阶段
ReadAndWrite.insert2("读者"+num+"正在读文件");
ReadAndWrite.ing.add("读者"+num+"正在读文件");
wait(random.nextInt(5000)+1500);
ReadAndWrite.insert2("读者"+num+"结束读文件");
ReadAndWrite.insert1("读者"+num+"完成读文件");
ReadAndWrite.ing.remove("读者"+num+"正在读文件");
ReadAndWrite.Re.remove(num+"打算读文件");
//以上为读文件的阶段
wait(3000);
ReadAndWrite.fresh.acquire(); //实现刷新页面时,线程的互斥
ReadAndWrite.refresh(); //刷新页面,通过队列的信息刷新页面
ReadAndWrite.fresh.release();
ReadAndWrite.mutex.acquire();
ReadAndWrite.count--; //文件读完了,读完一个出来一个,count--了
if(ReadAndWrite.count==0)
ReadAndWrite.rw.release();
ReadAndWrite.mutex.release();
}
} catch (InterruptedException e) {
System.out.println("读者"+num+"出现错误!");
e.printStackTrace();
}
try {
synchronized(this) {
Random random = new Random();
wait(random.nextInt(500));
ReadAndWrite.insert3("写者"+num+"打算写文件");
ReadAndWrite.Wr.add(num+"打算写文件");
ReadAndWrite.w.acquire();
ReadAndWrite.rw.acquire();
ReadAndWrite.insert2("写者"+num+"正在写文件");
ReadAndWrite.ing.add("写者"+num+"正在写文件");
wait(random.nextInt(10000)+3000);
ReadAndWrite.insert2("写者"+num+"结束写文件");
ReadAndWrite.insert3("写者"+num+"完成写文件");
ReadAndWrite.ing.remove("写者"+num+"正在写文件");
ReadAndWrite.Wr.remove(num+"打算写文件");
wait(3000);
ReadAndWrite.fresh.acquire();
ReadAndWrite.refresh();//刷新页面,通过队列的信息刷新页面
ReadAndWrite.fresh.release();
ReadAndWrite.rw.release();
ReadAndWrite.w.release();
}
} catch (InterruptedException e) {
System.out.println("写者"+num+"出现错误!");
e.printStackTrace();
}
运行界面:
2.银行家算法
银行家算法基于安全性算法实现,其目的是避免死锁方法中允许进程动态地申请资源,但系统在进行资源分配之前,应先计算此次分配资源的安全性,若分配不会导致系统进入不安全状态,则分配,否则等待。为实现银行家算法,系统必须设置若干数据结构。
int[][] Allocation = new int[ab][res];
int[][] Max = new int[ab][res];
int[][] Need = new int[ab][res];
int[] Available = new int[res];
int[] alloc_avail = new int[res]; //可用资源数
安全性算法:
设置工作向量Work,有m个元素,表示系统中的剩余可用资源数目。在执行安全性算法开始时,Work=Available。
- 初始化安全序列为空。
- 从Need矩阵中找到符合下面条件的行:该行对应的进程不在安全序列中,而且该行小于等于Work向量,找到后,把对应的进程加入安全序列;若找不到,则执行步骤4。
- 进程Pi进入安全序列后,可顺利执行,直至完成,并释放分配给它的资源,因此应执行Work=Work+Allocation[i],其中Allocation[i]表示进程Pi代表的在Allocation矩阵中对应的行,返回步骤2。
- 若此时安全序列中已有所有进程,则系统处于安全状态,否则系统处于不安全状态(不安全状态不意味着一定会发生死锁)。
核心代码如下:
while(true) {
f=0;
if(ip==ab) ip=0;
if(unsafe_chk[ip]==1 && tnp<=1) {
f=1;
break;
}
if(process_complete[ip] == 1) {
ip++;
continue;
} else {
for(c=0;c<res;c++) {
if(Available[c]<Need[ip][c]) f=1;
}
if(f==1) {
for(c=0;c<res;c++) {
if(alloc_avail[c]<Need[ip][c]) unsafe_chk[ip]=1;
}
ip++;
continue;
} else {
process_complete[ip]=1;
System.out.println("进程"+ip+"可以分配资源..");
System.out.println("进程终止,释放资源..");
System.out.println("释放后可用的资源有:");
for(c=0;c<res;c++) {
Available[c] += Allocation[ip][c];
System.out.print(Available[c]+" ");
}
System.out.println("\n");
ip++;
tnp--;
if(tnp==0) break;
}
}
}
}
if(tnp==0) System.out.println("Safe");
实现结果:
实现源码资源链接:实现源码资源链接https://download.csdn.net/download/zxl316616/85656014