操作系统

一、实验目的

进程调度是处理机管理的核心内容。本实验要求用高级语言编写模拟进程调度程序,以便加深理解有关进程控制块、进程队列等概念,并体会和了解优先数算法(包括抢占式和非抢占式)和时间片轮转算法的具体实施办法。

二、实验内容和要求

  1. 设计进程控制块PCB的结构,通常应包括如下信息:

进程名、进程优先数(时间片轮转算法中本次轮转需要的剩余时间片数)、进程已占用的CPU时间、进程到完成还需要的时间、进程的状态、当前队列指针等。

  1. 编写两种调度算法程序:

优先数调度算法程序(包括抢占式和非抢占式)

循环轮转调度算法程序

  1. 程序源代码和运行截图写入实验报告并提交

、实验步骤

  1. 实验准备

(1) 查阅相关资料;

(2) 初步编写程序;

(3) 准备测试数据; 

  1. 源代码

package caozuoxitong;

 

import java.util.Scanner;

 

class PCB {

String name; // 进程的名字

int prio; // 进程的优先级

int round; // 分配 CPU 的时间片

int cputime; // CPU 执行时间

int needtime; // 进程执行所需要的时间

char state; // 进程的状态, W——就绪, R——执行, F——完成

int count; // 记录执行的次数

PCB next; // 链表指针

 

PCB(String name, int needtime) {

this.name = name;

this.needtime = needtime;

this.cputime = 0;

this.state = 'W';

this.count = 0;

this.round = 2;

this.prio = 50 - needtime; // 设置进程优先值初值

}

}

 

public class test {

static PCB ready = null, run = null, finish = null, tail = null; // 定义三个队列,就绪队列头,执行队列头和完成队列头,就绪队列尾

static int N;

 

public static void main(String[] args) {

Scanner scanner = new Scanner(System.in);

char chose = ' ';

while (chose != 'q' && chose != 'Q') {

System.out.println("选择进程优先级算法(抢占式)请输入P,选择循环轮转算法请输入R,选择循环轮转算法(非抢占式)请输入I,退出请输入Q");

System.out.print("请输入你的选择:");

chose = scanner.next().charAt(0);

if (chose != 'q' && chose != 'Q') {

if (chose == 'P' || chose == 'p') {

priorInit(chose);

priority(chose);

} else if (chose == 'r' || chose == 'R') {

roundrunInit(chose);

roundrun(chose);

}

else if (chose == 'I' || chose == 'i') {

priorInit2(chose);

priority2(chose);

}

}

}

System.out.println("谢谢使用!");

scanner.close();

}

 

static void firstin() { // 调度就绪队列的第一个进程投入运行

if (ready != null) {

run = ready;

ready = ready.next;

run.state = 'R';

run.next = null;

} else {

run = null;

}

}

 

static void print1(char a) { // 打印表头行信息

if (Character.toUpperCase(a) == 'P') {

System.out.println("name cputime needtime prio state");

} else {

System.out.println("name cputime needtime count round state");

}

}

 

static void print2(char chose, PCB p) { // 打印每一行的状态信息

if (Character.toUpperCase(chose) == 'P') {

System.out.printf("%s\t%d\t%d\t%d\t%c\n", p.name, p.cputime, p.needtime, p.prio, p.state);

} else {

System.out.printf("%s\t%d\t%d\t%d\t%d\t%c\n", p.name, p.cputime, p.needtime, p.count, p.round, p.state);

}

}

 

static void print(char chose) { // 打印每执行一次算法后所有的进程的状态信息

PCB p;

print1(chose);

if (run != null) {

print2(chose, run);

}

p = ready;

while (p != null) {

print2(chose, p);

p = p.next;

}

p = finish;

while (p != null) {

print2(chose, p);

p = p.next;

}

}

 

static void insertPrio(PCB q) { // 在优先数算法中,将尚未完成的PCB按优先数顺序插入到就绪队列中

PCB p = ready, r = null;

if (q.prio > ready.prio) { // 要插入的进程的优先级大于ready 的优先级

q.next = ready;

ready = q;

} else { // 要插入的进程的优先级不大于ready 的优先级

while (p != null && p.prio >= q.prio) {

r = p;

p = p.next;

}

q.next = p;

if (r != null) {

r.next = q;

}

}

}

 

static void priorInit(char chose) { // 进程优先级法初始化将进程按优先级插入到就绪队列里

Scanner scanner = new Scanner(System.in);

System.out.println("输入进程的个数N:");

N = scanner.nextInt();

for (int i = 0; i < N; i++) {

System.out.printf("输入第%d个进程名\n", i + 1);

String na = scanner.next();

System.out.println("完成进程需要的时间片数");

int time = scanner.nextInt();

PCB p = new PCB(na, time);

if (ready == null) {

ready = p;

ready.next = null;

} else {

insertPrio(p);

}

System.out.println("当前就绪队列的进程的信息");

print(chose);

}

System.out.printf("%d个进程已按优先级从高到低进到就绪队列中\n", N);

System.out.println("按回车键开始模拟优先级算法....");

scanner.nextLine();

scanner.nextLine();

firstin();

}

 

static void priority(char chose) { // 进程优先级算法总函数

while (run != null) {

run.cputime += 1;

run.needtime -= 1;

run.prio -= 1;

if (run.needtime == 0) {

run.next = finish;

finish = run;

run.state = 'F';

run.prio = 0;

run = null;

firstin();

} else {

if (ready != null && run.prio < ready.prio) {

run.state = 'W';

insertPrio(run);

run = null;

firstin();

}

}

print(chose);

}

}

static void priorInit2(char chose) { // 进程优先级法初始化将进程按优先级插入到就绪队列里

Scanner scanner = new Scanner(System.in);

System.out.println("输入进程的个数N:");

N = scanner.nextInt();

for (int i = 0; i < N; i++) {

System.out.printf("输入第%d个进程名\n", i + 1);

String na = scanner.next();

System.out.println("完成进程需要的时间片数");

int time = scanner.nextInt();

PCB p = new PCB(na, time);

if (ready == null) {

ready = p;

ready.next = null;

} else {

insertPrio(p);

}

System.out.println("当前就绪队列的进程的信息");

print(chose);

}

System.out.printf("%d个进程已按优先级从高到低进到就绪队列中\n", N);

System.out.println("按回车键开始模拟优先级算法....");

scanner.nextLine();

scanner.nextLine();

firstin();

}

 

static void priority2(char chose) { // 进程优先级算法总函数

{

while (run != null) {

run.cputime += 1;

run.needtime -= 1;

run.prio -= 1;

if (run.needtime == 0) {

run.next = finish;

finish = run;

run.state = 'F';

run.prio = 0;

run = null;

firstin();

}

print(chose);

}

}

 

}

 

static void insertRr(PCB q) { // 在轮转法中,将执行了一个时间片单位(为2),但尚未完成的进程的PCB,插到就绪队列的队尾

tail.next = q;

tail = q;

q.next = null;

}

 

static void roundrunInit(char chose) { // 循环轮转法初始化将就绪队列保存为FIFO队列

Scanner scanner = new Scanner(System.in);

System.out.println("\t\t循环轮转算法模拟全过程\n\n");

System.out.println("输入进程的个数N:");

N = scanner.nextInt();

for (int i = 0; i < N; i++) {

System.out.printf("输入第%d个进程名\n", i + 1);

String na = scanner.next();

System.out.println("完成进程需要的时间片数");

int time = scanner.nextInt();

PCB p = new PCB(na, time);

if (ready != null) {

insertRr(p);

} else {

ready = p;

tail = p;

}

System.out.println("当前就绪队列的进程的信息");

print(chose);

}

System.out.printf("%d 个进程已按FIFO进到就绪队列中\n", N);

System.out.println("按回车键开始模循环轮转算法......");

scanner.nextLine();

scanner.nextLine();

run = ready;

ready = ready.next;

run.state = 'R';

}

 

static void roundrun(char chose) { // 循环轮转法总算法

while (run != null) {

run.cputime += 1;

run.needtime -= 1;

run.count += 1;

if (run.needtime == 0) {

run.next = finish;

finish = run;

run.state = 'F';

run.prio = 0;

run = null;

if (ready != null) {

firstin();

}

} else {

if (run.count == run.round) {

run.count = 0;

if (ready != null) {

run.state = 'W';

insertRr(run);

firstin();

}

}

}

print(chose);

}

}

}

 

 

 

 

 

  1. 测试数据

优先级算法(抢占式)

 

 

选择循环轮转算法

 

 

 

选择循环轮转算法(非抢占式)

 

 

 

  1. 运行结果

优先级算法(抢占式)

 

选择循环轮转算法

 

选择循环轮转算法(非抢占式)

 

四、遇到的主要问题和解决方法

问题:队列是先进先出的 , 在优先级算法中怎么来向插入新的进程 , 使其能够按优先级排序 。

解决方法: 使用链表可以完美解决。

问题: 低优先级的进程始终被高优先级的进程抢占,那么低优先级进程可能会长时间等待而无法执行,产生进程饥饿问题。

解决方法:

优先级衰减: 可以尝试提高他的优先级,知道可以执行。

 

五、实验总结

通过本次实验,学习了优先数调度算法程序(包括抢占式和非抢占式),循环轮转调度算法程序,对进程的调度有了更深的了解。优先级调度算法可以根据进程的优先级来确定执行顺序。在非抢占式算法中,进程一旦开始执行,将一直运行,而在抢占式算法中,更高优先级的进程可以随时抢占CPU。循环轮转调度算法中,每个进程被分配一个时间片来运行。时间片结束后,进程被放入就绪队列的末尾,调度器选择队列中的下一个进程来运行。在实际中,选择合适的算法,可以提高性能和用户的体验。

posted @ 2024-06-11 23:34  布吉岛???  阅读(10)  评论(0编辑  收藏  举报