浙江理工大学
基于java的课程设计题目《操作系统课程设计》
课程设计报告
2016~2017学年第1学期
学 院 | 信息学院 |
班 级 | 14数字媒体技术2班 |
姓 名 | 黄宇达、沈宁 |
学 号 | 2014329700042 2014329700046 |
任课教师 | 桂宁 |
数字媒体技术专业
2017年1月
《操作系统课程设计》实 验 报 告
实验名称:操作系统课程设计 | 实验地点:10-414 |
所使用的工具软件及环境: Win7系统,Eclipse | |
一、实验目的: 操作系统原理是计算机专业的核心课程。本课程设计的目的旨在加深学生对计算机操作系统内核的理解,提高对操作系统内核的分析与扩展能力。在课程理论教学中,较多地是讲解操作系统理论和实现原理。 在阅读Linux操作系统源代码的基础上完成两个主要Project。题目可选做A类或者B类,或者C类,或者自主命题。 A、本课程设计要求学生在阅读Linux操作系统源代码的基础上完成如下两个主要Project: 1、在Linux2.4的内核中添加新的系统调用,以理解系统调用的工作机制,掌握扩展内核功能的技术。 2、在Linux2.4中修改调度程序的代码,扩展一个新的调度算法 B、在Java虚拟机上完成如下两个Project(2,3选一): 1、基于java虚拟机的线程调度 2、请求页式管理的Java实现 3. 用JAVA语言模仿“生产者—消费者问题 C、方向命题,具体内容不限,任选2题; D、自主命题。 | |
二、实验内容: 该小组为二人小组,选择完成B类中的以下两个任务 1、基于java虚拟机的线程调度 3、用JAVA语言模仿“生产者—消费者问题 具体实验内容如下 ·基于java虚拟机的线程调度 1、 Java线程的优先级机制及调度机制 2、用Java语言实现基于优先级的轮转线程调度 至少创建5个线程并输出它们在上述调度算法下的调度情况,并输出到终端,以检查算法的执行情况 ·用JAVA语言模仿“生产者—消费者问题” 1.通过Java语言中的wait()和notify()命令模拟操作系统中的P/V操作; 2.为每个生产者/消费者产生一个线程,设计正确的同步算法 3.每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的当前全部内容、 当前指针位置和生产者/消费者线程的自定义标识符。 4.生产者和消费者各有两个以上。 多个生产者或多个消费者之间须共享对缓冲区进行操作的函数代码。 | |
三、源代码 1.基于java虚拟机的线程调度 /*起始化类*/ import java.util.ArrayList; import java.util.List; public class Process { public static List<double []> task_info=new ArrayList<>();//进程列表 public static int task_num=5;//进程数 public static void init_task()//初始化进程列表 { for(int i=0;i<task_num;i++) { double[] t=new double[4]; t[0]=i;//进程号 t[1]=0;//到达时间 t[2]=0;//响应比 t[3]=(int)(Math.random()*100)%20+1;//需要运行时间 task_info.add(t); } } public static void main(String arg[]) { Process.init_task();//初始化进程列表 System.out.println("\n\n==========================时间片轮转======================"); RR.init_task(task_info,task_num); RR.CircleTime();//时间片轮转 } } /*主类*/ SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import urrent.ArrayBlockingQueue; /** * Created by 32706 on 2016/12/8. * 时间片轮转调度算法 */ public class RR { private static SimpleDateFormat tm= new SimpleDateFormat("HH:mm:ss"); private static int task_num=5; private static int Circle_size=4;//定义时间片大小 public static ArrayBlockingQueue task_q=new ArrayBlockingQueue(task_num);//进程队列 private static List<double[]> execute_time=new ArrayList<>();//进程执行时间 public static void CircleTime() { try { while (true) { double[] t = new double[4]; t = (double[])task_q.take(); int current_task_time=(int)t[3]; int task_NO=(int)t[0]; System.out.print(tm.format(new Date())+"第" +task_NO+"号进程开始运行===="); if(current_task_time<=Circle_size)//如果能够在本时间片中运行完成 { Thread.sleep((long) current_task_time*1000);//模拟运行所需时间 System.out.println(tm.format(new Date())+"结束执行=====本次用时"+current_task_time+"S"); double[] exe_t=new double[2]; exe_t[0]=task_NO; exe_t[1]=System.currentTimeMillis()-t[1];//计算该进程所用的周转时间 execute_time.add(exe_t);//加入到周转时间队列 } else {//如果不能再本次时间片中运行完 t[3]=t[3]-Circle_size; task_q.put(t); Thread.sleep(Circle_size*1000); System.out.println(tm.format(new Date())+"本次时间片用完~~~~~进程等待"); } if(task_q.size()==0)//如果进程队列为空了,就退出循环 break; } } catch (Exception e) { } show_time();//显示每个进程的调度时间 } public static void show_time()//显示每个进程的调度时间 { double sum_time=0; for(int i=0;i<execute_time.size();i++) { double[] t=(i); System.out.println("task:"+t[0]+":周转时间="+(int)(t[1]/1000)+"S"); sum_time+=t[1]; } System.out.println("使用时间片轮转的策略,平均周转时间为:"+(int)(sum_time/execute_time.size()/1000)+"S"); } static void init_task(List<double []> in,int tn)//初始化进程列表 { task_num=tn; for(int i=0;i<task_num;i++) { double [] (i); t[1] = System.currentTimeMillis();//获得进程到达时间 try { task_q.put(t); } catch (InterruptedException e) { e.printStackTrace(); } } } } ·用JAVA语言模仿“生产者—消费者问题” import java.util.LinkedList; public class Storage { // 仓库最大存储量 private final int MAX_SIZE = 100; // 仓库存储的载体 private LinkedList<Object> list = new LinkedList<Object>(); // 生产num个产品 public void produce(int num) { // 同步代码段 synchronized (list) { // 如果仓库剩余容量不足 while (list.size() + num > MAX_SIZE) { System.out.println("【要生产的产品数量】:" + num + "/t【库存量】:" + list.size() + "/t暂时不能执行生产任务!"); try { // 由于条件不满足,生产阻塞 list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 生产条件满足情况下,生产num个产品 for (int i = 1; i <= num; ++i) { list.add(new Object()); } System.out.println("【已经生产产品数】:" + num + "/t【现仓储量为】:" + list.size()); ifyAll(); } } // 消费num个产品 public void consume(int num) { // 同步代码段 synchronized (list) { // 如果仓库存储量不足 while (list.size() < num) { System.out.println("【要消费的产品数量】:" + num + "/t【库存量】:" + list.size() + "/t暂时不能执行生产任务!"); try { // 由于条件不满足,消费阻塞 list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 消费条件满足情况下,消费num个产品 for (int i = 1; i <= num; ++i) { ve(); } System.out.println("【已经消费产品数】:" + num + "/t【现仓储量为】:" + list.size()); ifyAll(); } } // get/set方法 public LinkedList<Object> getList() { return list; } public void setList(LinkedList<Object> list) { this.list = list; } public int getMAX_SIZE() { return MAX_SIZE; } } public class Producer extends Thread { // 每次生产的产品数量 private int num; // 所在放置的仓库 private Storage storage; // 构造函数,设置仓库 public Producer(Storage storage) { this.storage = storage; } // 线程run函数 public void run() { produce(num); } // 调用仓库Storage的生产函数 public void produce(int num) { storage.produce(num); } // get/set方法 public int getNum() { return num; } public void setNum(int num) { this.num = num; } public Storage getStorage() { return storage; } public void setStorage(Storage storage) { this.storage = storage; } } public class Consumer extends Thread { // 每次消费的产品数量 private int num; // 所在放置的仓库 private Storage storage; // 构造函数,设置仓库 public Consumer(Storage storage) { this.storage = storage; } // 线程run函数 public void run() { consume(num); } // 调用仓库Storage的生产函数 public void consume(int num) { sume(num); } // get/set方法 public int getNum() { return num; } public void setNum(int num) { this.num = num; } public Storage getStorage() { return storage; } public void setStorage(Storage storage) { this.storage = storage; } } public class Test { public static void main(String[] args) { // 仓库对象 Storage storage = new Storage(); // 生产者对象 Producer p1 = new Producer(storage); Producer p2 = new Producer(storage); Producer p3 = new Producer(storage); Producer p4 = new Producer(storage); Producer p5 = new Producer(storage); Producer p6 = new Producer(storage); Producer p7 = new Producer(storage); // 消费者对象 Consumer c1 = new Consumer(storage); Consumer c2 = new Consumer(storage); Consumer c3 = new Consumer(storage); // 设置生产者产品生产数量 p1.setNum(10); p2.setNum(10); p3.setNum(10); p4.setNum(10); p5.setNum(10); p6.setNum(10); p7.setNum(80); // 设置消费者产品消费数量 c1.setNum(50); c2.setNum(20); c3.setNum(30); // 线程开始执行 c1.start(); c2.start(); c3.start(); p1.start(); p2.start(); p3.start(); p4.start(); p5.start(); p6.start(); p7.start(); } } 四、实验结果测试、收获与体会: 1.组内分工 黄宇达:主要负责用JAVA语言模仿“生产者—消费者问题”,进行工作安排,代码完善以及修改,完善实验报告。 沈宁:主要基于java虚拟机的线程调度。分析实验过程。代码完善以及修改。 小组答辩时间:1月6日 2.基于java虚拟机的线程调度 根据要求,设置了0~4五个进程。实时任务调度策略,时间片轮转。将时间片设置为4s。当任务的时间片用完,系统将重新分配时间片,并置于就绪队列尾。放在队列尾。 保证了所有具有相同优先级的RR任务的调度公平。 最终输出每个进程的周转时间和总平均周转时间。 设计思路主要围绕着时间片为中心,规划好进程列表,并随机生成每个进程完成所需要的时间。进行时间轮转。当时间片用完,将进程放置于就绪队列的尾部进行排列。 并用Thread.sleep将进程进行休眠,以达到真实的模拟效果。 在真实系统中这种调度策略是从所有处于就绪状态的线程中选择优先级最高的线程分配一定的CPU时间运行。该时间过后再选择其他线程运行。只有当线程运行结束、放弃(yield)CPU或由于某种原因进入阻塞状态,低优先级的线程才有机会执行。如果有两个优先级相同的线程都在等待CPU,则调度程序以轮转的方式选择运行的线程。 3用JAVA语言模仿“生产者—消费者问题” 实验结果演示: 首先在实验开始之前,必须搞清楚概念。 生产者消费者问题,也称有限缓冲问题,是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。 生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。 该问题的关键就是 要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。 要解决这个问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。 当概念清楚之后,设计思路也就很清晰了。我们需要的是一个虚拟的缓冲区,并且要有一定量的消费者和生产者来对缓冲区添加数据和消耗数据。 并且通过Java语言中的wait()和notify()命令模拟操作系统中的唤醒和等待操作。 当生产者生产数量满足不了消费者产品消耗时,消费者将被wait().等待生产者生产足够的数量才notifyAll()将消费者唤醒。 实验感悟: 基于java虚拟机的线程调度的实验,我们这次通过利用了时间片转轮调度算法,来实现多个线程的调度,与此同时也保障了相同优先级任务的时间公平,实验过程中,也遇到了一些麻烦,为了解决这些麻烦,我们也在网上查阅了一些相关的资料,通过借鉴和改善相应的代码和意见,最后终于实现了实验指导书上的要求。 而另一个用JAVA语言模仿“生产者—消费者问题”的实验,一看到这个实验,虽然之前没有印象,但却有似明非明的感觉,然后和组员一讨论,发现上个多线程实验正好用到了相关的知识,这次正好可以巩固之前的知识再对其进行实际的应用。而这个实验也有一点不同之处,那就是缓冲区的处理,当然这也是相当容易实现的。 总之,通过这次课程设计,我们更加清楚的理解了多线程相关方面的知识,也通过“生产者——消费者问题”,对所学到的知道进行了进一步巩固,有很大的收获。 | |
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论