├── .idea
├── artifacts
│ └── OSLab1_Scheduler_jar.xml
├── encodings.xml
├── misc.xml
├── modules.xml
├── vcs.xml
└── workspace.xml
├── OSLab1-Scheduler.iml
├── README.md
├── labs-2019.zip
├── out
├── artifacts
│ └── OSLab1_Scheduler_jar
│ │ └── OSLab1-Scheduler.jar
└── production
│ └── OSLab1-Scheduler
│ ├── Main.class
│ ├── PCB.class
│ ├── Process$State.class
│ ├── Process.class
│ ├── Queue.class
│ ├── Resource$BlockProcess.class
│ └── Resource.class
├── src
├── Main.java
├── PCB.java
├── Process.java
├── Queue.java
└── Resource.java
├── test
├── 0.txt
├── 1.txt
├── 2.txt
├── 3.txt
├── 4.txt
├── 5.txt
├── OSLab1-Scheduler.jar
├── README.md
├── 读取文件模式.bat
└── 键盘录入模式.bat
├── 关文聪 2016060601008 计算机操作系统 实验报告.docx
├── 关文聪 2016060601008 计算机操作系统 实验报告.pdf
└── 实验报告模板.docx
/.idea/artifacts/OSLab1_Scheduler_jar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | $PROJECT_DIR$/out/artifacts/OSLab1_Scheduler_jar
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 | 1557675970383
206 |
207 |
208 | 1557675970383
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 | OSLab1-Scheduler:jar
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 | 1.8
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
--------------------------------------------------------------------------------
/OSLab1-Scheduler.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Operating-System-Experiment
2 | UESTC-Operating System Experiment(电子科技大学 操作系统 实验)
3 |
4 | ## 一、进程与资源管理实验
5 |
6 | ### Introduction
7 | 在实验室提供的软硬件环境中,设计并实现一个基本的进程与资源管理器。该管理器能够完成进程的控制,如进程创建与撤销、进程的状态转换;能够基于优先级调度算法完成进程的调度,模拟时钟中断,在同优先级进程中采用时间片轮转调度算法进行调度;能够完成资源的分配与释放,并完成进程之间的同步。该管理器同时也能完成从用户终端或者指定文件读取用户命令,通过Test shell模块完成对用户命令的解释,将用户命令转化为对进程与资源控制的具体操作,并将执行结果输出到终端或指定文件中。
8 |
9 | **具体实现见源码**
10 |
11 | ### 测试文件与测试用例
12 |
13 | #### 使用
14 |
15 | 编辑修改批处理文件中的文件名,运行批处理文件(需要本机配置好Java环境)
16 |
17 | #### 鸣谢
18 |
19 | [同学们提供的测试用例若干](https://github.com/502408764/os-test-shell)
20 |
21 | ## 二、虚拟内存综合实验
22 |
23 | ### Introduction
24 |
25 | 通过手工查看系统内存,并修改特定物理内存的值,实现控制程序运行的目的。
26 |
27 | **具体实现见实验报告**
28 |
--------------------------------------------------------------------------------
/labs-2019.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eternity-Myth/Operating-System-Experiment/3bcd08379ed723a3958d685ffbf37d790640a8a8/labs-2019.zip
--------------------------------------------------------------------------------
/out/artifacts/OSLab1_Scheduler_jar/OSLab1-Scheduler.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eternity-Myth/Operating-System-Experiment/3bcd08379ed723a3958d685ffbf37d790640a8a8/out/artifacts/OSLab1_Scheduler_jar/OSLab1-Scheduler.jar
--------------------------------------------------------------------------------
/out/production/OSLab1-Scheduler/Main.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eternity-Myth/Operating-System-Experiment/3bcd08379ed723a3958d685ffbf37d790640a8a8/out/production/OSLab1-Scheduler/Main.class
--------------------------------------------------------------------------------
/out/production/OSLab1-Scheduler/PCB.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eternity-Myth/Operating-System-Experiment/3bcd08379ed723a3958d685ffbf37d790640a8a8/out/production/OSLab1-Scheduler/PCB.class
--------------------------------------------------------------------------------
/out/production/OSLab1-Scheduler/Process$State.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eternity-Myth/Operating-System-Experiment/3bcd08379ed723a3958d685ffbf37d790640a8a8/out/production/OSLab1-Scheduler/Process$State.class
--------------------------------------------------------------------------------
/out/production/OSLab1-Scheduler/Process.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eternity-Myth/Operating-System-Experiment/3bcd08379ed723a3958d685ffbf37d790640a8a8/out/production/OSLab1-Scheduler/Process.class
--------------------------------------------------------------------------------
/out/production/OSLab1-Scheduler/Queue.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eternity-Myth/Operating-System-Experiment/3bcd08379ed723a3958d685ffbf37d790640a8a8/out/production/OSLab1-Scheduler/Queue.class
--------------------------------------------------------------------------------
/out/production/OSLab1-Scheduler/Resource$BlockProcess.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eternity-Myth/Operating-System-Experiment/3bcd08379ed723a3958d685ffbf37d790640a8a8/out/production/OSLab1-Scheduler/Resource$BlockProcess.class
--------------------------------------------------------------------------------
/out/production/OSLab1-Scheduler/Resource.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eternity-Myth/Operating-System-Experiment/3bcd08379ed723a3958d685ffbf37d790640a8a8/out/production/OSLab1-Scheduler/Resource.class
--------------------------------------------------------------------------------
/src/Main.java:
--------------------------------------------------------------------------------
1 |
2 | import java.io.*;
3 | import java.util.Scanner;
4 |
5 | public class Main {
6 | private static final PCB pcb = PCB.getPCB();// 生成PCB
7 |
8 | // 生成4个资源R1、R2、R3、R4,并设定资源数量
9 | private static final Resource R1 = new Resource(1, 1);
10 | private static final Resource R2 = new Resource(2, 2);
11 | private static final Resource R3 = new Resource(3, 3);
12 | private static final Resource R4 = new Resource(4, 4);
13 |
14 | public static void main(String[] args) throws IOException {
15 |
16 | pcb.createProcess("init", 0); // 创建init进程,优先级设定为0
17 | System.out.print("init" + " ");
18 | if (args.length != 0) { // 有命令行参数时,从文件读取
19 | loadFile(args[0]);
20 | } else { // 无命令行参数时,从键盘录入
21 | System.out.println();
22 | Scanner scanner = new Scanner(System.in); //scanner接收输入
23 | while (scanner.hasNextLine()) {
24 | String input = scanner.nextLine();
25 | if (input.trim().equals("")) { //空命令时继续接收
26 | continue;
27 | }
28 | exec(input);
29 | }
30 | }
31 | }
32 |
33 | // 对输入的命令进行处理,适用于键盘录入或者文件读入
34 | public static void exec(String input) {
35 | String[] commands = new String[]{input};
36 | for (String command : commands) { //对不同的输入命令进行处理
37 | String[] cmds = command.split("\\s+");
38 | String options = cmds[0];
39 | switch (options) {
40 | // case "init":
41 | // if (pcb.findProcess("init") != null) { // 已经完成了初始化,系统中已经有init进程
42 | // System.out.println("错误!已完成过初始化!init进程已存在!");
43 | // } else {
44 | // pcb.createProcess("init", 0); // 创建init进程,优先级设定为0
45 | // System.out.println("初始化成功!init进程已创建!");
46 | // }
47 | // break;
48 | case "cr":
49 | // if (pcb.findProcess("init") == null) { // 检查是否完成了初始化
50 | // System.out.println("错误!系统未初始化!请先执行init命令初始化!");
51 | // } else
52 | if (cmds.length != 3) { // 检查输入格式是否正确
53 | System.out.println("错误!请输入合法的参数!");
54 | } else {
55 | String processName = cmds[1];
56 | int priority = 0;
57 | try { // 检查优先级的输入是否正确
58 | priority = Integer.parseInt(cmds[2]);
59 | if (priority <= 0 || priority > 2) {
60 | System.out.println("错误!请输入合法的参数!");
61 | continue;
62 | }
63 | } catch (Exception e) {
64 | System.out.println("错误!请输入合法的参数!");
65 | }
66 | if (pcb.exsitName(processName)) { // 检查用户输入的进程名是否已经存在
67 | System.out.println("错误!进程名" + processName + "已经存在!请选择其它的进程名!");
68 | break;
69 | }
70 | pcb.createProcess(processName, priority);
71 | }
72 | break;
73 | case "de":
74 | // if (pcb.findProcess("init") == null) { // 检查是否完成了初始化
75 | // System.out.println("错误!系统未初始化!请先执行init命令初始化!");
76 | // } else
77 | if (cmds.length != 2) { // 检查输入格式是否正确
78 | System.out.println("错误!请输入合法的参数!");
79 | } else {
80 | String processName = cmds[1];
81 | Process process = pcb.findProcess(processName);
82 | if (process == null) { // 检查用户输入的进程名是否已经存在
83 | System.out.println("错误!没有名为" + processName + "的进程!");
84 | } else if (processName.equals("init")) { // 设定不允许用户删除系统init进程
85 | System.out.println("错误!您没有权限终止init进程!");
86 | } else {
87 | process.destroy();
88 | // process.killSubTree(); // 将进程自身包括其所有子进程终止
89 | // PCB.scheduler();
90 | // System.out.println("终止进程成功!");
91 | }
92 | }
93 | break;
94 | case "req":
95 | // if (pcb.findProcess("init") == null) { // 检查是否完成了初始化
96 | // System.out.println("错误!系统未初始化!请先执行init命令初始化!");
97 | // } else
98 | if (cmds.length != 3) { // 检查输入格式是否正确
99 | System.out.println("错误!请输入合法的参数!");
100 | } else {
101 | String resourceName = cmds[1];
102 | int needNum = 0;
103 | try {
104 | needNum = Integer.parseInt(cmds[2]);
105 | } catch (Exception e) {
106 | System.out.println("错误!请输入合法的参数!");
107 | }
108 | Process currentProcess = pcb.getCurrentProcess(); // 获取当前进程
109 | switch (resourceName) { // 检查资源名称,请求对应资源
110 | case "R1":
111 | R1.request(currentProcess, needNum);
112 | break;
113 | case "R2":
114 | R2.request(currentProcess, needNum);
115 | break;
116 | case "R3":
117 | R3.request(currentProcess, needNum);
118 | break;
119 | case "R4":
120 | R4.request(currentProcess, needNum);
121 | break;
122 | default:
123 | System.out.println("错误!请输入合法的参数!");
124 | }
125 | }
126 | break;
127 | case "rel":
128 | // if (pcb.findProcess("init") == null) { // 检查是否完成了初始化
129 | // System.out.println("错误!系统未初始化!请先执行init命令初始化!");
130 | // } else
131 | if (cmds.length != 3) { // 检查输入格式是否正确
132 | System.out.println("错误!请输入合法的参数!");
133 | } else {
134 | String resourceName = cmds[1];
135 | int relNum = 0;
136 | try {
137 | relNum = Integer.parseInt(cmds[2]);
138 | } catch (Exception e) {
139 | System.out.println("错误!请输入合法的参数!");
140 | }
141 | Process currentProcess = pcb.getCurrentProcess(); // 获取当前进程
142 | switch (resourceName) { // 检查资源名称,释放对应资源
143 | case "R1":
144 | R1.release(currentProcess, relNum);
145 | break;
146 | case "R2":
147 | R2.release(currentProcess, relNum);
148 | break;
149 | case "R3":
150 | R3.release(currentProcess, relNum);
151 | break;
152 | case "R4":
153 | R4.release(currentProcess, relNum);
154 | break;
155 | default:
156 | System.out.println("错误!请输入合法的参数!");
157 | }
158 | }
159 | break;
160 | case "to":
161 | pcb.timeout();
162 | break;
163 | case "lp":
164 | // if (pcb.findProcess("init") == null) { // 检查是否完成了初始化
165 | // System.out.println("错误!系统未初始化!请先执行init命令初始化!");
166 | // }
167 | if (cmds.length == 1) { // lp命令打印所有进程树和信息
168 | pcb.printProcessTree(pcb.findProcess("init"), 0);
169 | } else if (cmds.length < 3 || !cmds[1].equals("-p")) { // lp -p pname命令打印某具体进程的信息
170 | System.out.println("错误!请输入合法的参数或命令!");
171 | } else {
172 | String pname = cmds[2];
173 | Process process = pcb.findProcess(pname);
174 | if (process == null) {
175 | System.out.println("错误!没有名为" + pname + "的进程!");
176 | } else {
177 | pcb.printProcessDetail(process);
178 | }
179 | }
180 | break;
181 | case "lr":
182 | R1.printCurrentStatus();
183 | R2.printCurrentStatus();
184 | R3.printCurrentStatus();
185 | R4.printCurrentStatus();
186 | break;
187 | case "help":
188 | printHelp();
189 | break;
190 | case "exit":
191 | System.out.println("Good Bye!");
192 | System.exit(0);
193 | // case"list":
194 | // pcb.printExistProcess();
195 | // break;
196 | default:
197 | System.out.println("错误!请输入合法的命令!");
198 | break;
199 | }
200 | }
201 | if (pcb.getCurrentProcess() != null) {
202 | System.out.print(pcb.getCurrentProcess().getProcessName() + " ");
203 | }
204 | }
205 |
206 | // 以读文件的方式运行系统
207 | private static void loadFile(String filePath) throws IOException {
208 | InputStream in = new FileInputStream(filePath);
209 | LineNumberReader reader = new LineNumberReader(new FileReader(filePath));
210 | String cmd = null;
211 | while ((cmd = reader.readLine()) != null) {
212 | if (!"".equals(cmd)) {
213 | exec(cmd);
214 | }
215 | }
216 | }
217 |
218 | private static void printHelp() {
219 | System.out.println("-----------------------------------------------------------------------------------------------------");
220 | System.out.println(" cr pname priority: 创建新进程并指定进程名与优先级(0,1,2)");
221 | System.out.println(" de pname: 按照特定进程名终止某进程(init进程除外,不允许终止init进程)");
222 | System.out.println(" req RID num: 为当前正在运行的进程请求指定数量的资源");
223 | System.out.println(" rel RID: 为当前正在运行的进程释放某特定的所有资源");
224 | System.out.println(" rel RID num: 为当前正在运行的进程释放某特定的指定数量的资源");
225 | System.out.println(" to: 当前正在运行的时间片完");
226 | System.out.println(" lp: 打印所有进程的信息");
227 | System.out.println(" lp -p pname: 指定进程名打印某特定进程的信息");
228 | System.out.println(" lr: 打印所有资源的信息");
229 | System.out.println(" exit: 退出系统");
230 | System.out.println(" help: 输出此帮助信息");
231 | System.out.println("By UESTC-关文聪 2016060601008");
232 | System.out.println("-----------------------------------------------------------------------------------------------------");
233 | }
234 | }
235 |
--------------------------------------------------------------------------------
/src/PCB.java:
--------------------------------------------------------------------------------
1 | import java.util.*;
2 | import java.util.concurrent.ConcurrentHashMap;
3 | import java.util.concurrent.atomic.AtomicInteger;
4 |
5 | /**
6 | * PCB(进程管理块)类,用于进程的管理
7 | */
8 | public class PCB {
9 | private static final PCB pcb = new PCB();// 单例设计模式-饿汉式
10 | private static final Queue readyQueue = Queue.getReadyQueue(); //生成就绪队列
11 |
12 | public static PCB getPCB() {
13 | return pcb;
14 | }
15 |
16 | private static Map existProcesses;// 所有存活的进程,包括Running(运行状态),Blocked(阻塞状态),Ready(就绪状态)
17 | private Process currentProcess;// 当前占用CPU的进程
18 | private AtomicInteger pidGenerator;// pid生成器,用以生成唯一的pid
19 |
20 | private PCB() {
21 | existProcesses = new HashMap<>();
22 | pidGenerator = new AtomicInteger();
23 | }
24 |
25 | public Process getCurrentProcess() {
26 | return currentProcess;
27 | }
28 |
29 | public void setCurrentProcess(Process currentProcess) {
30 | this.currentProcess = currentProcess;
31 | }
32 |
33 | // 生成PID号(以自增方式生成保证不重复)
34 | public int generatePID() {
35 | return pidGenerator.getAndIncrement();
36 | }
37 |
38 | // 每个进程一经创建,便会调用该方法,将其放在ExistList中
39 | public void addExistList(Process process) {
40 | existProcesses.put(process.getProcessName(), process);
41 | }
42 |
43 | // 创建新进程
44 | public Process createProcess(String processName, int priority) {
45 | Process currentProcess = pcb.getCurrentProcess();
46 | // 为新建进程分配PID,进程名,优先级,进程状态,资源,父进程和子进程信息等
47 | Process process = new Process(pcb.generatePID(), processName, priority, Process.State.NEW, new ConcurrentHashMap<>(), currentProcess, new LinkedList<>());
48 | if (currentProcess != null) { // 排除创建的进程为第一个进程的特殊情况
49 | currentProcess.getChildren().add(process);// 新创建进程作为当前进程的子进程
50 | process.setParent(currentProcess); // 旧进程作为新创建进程的父进程
51 | }
52 | pcb.addExistList(process); // 将新创建的进程放在ExistList中
53 | readyQueue.addProcess(process);// 将新创建的进程放入就绪队列中
54 | process.setState(Process.State.READY); // 成功进入就绪队列的进程,其状态将置为就绪状态
55 | PCB.scheduler(); // 调度
56 | return process;
57 | }
58 |
59 | // 主要用于判断用户输入的进程名称是否合法,因为name对用户来说是进程唯一标识
60 | public static boolean exsitName(String name) {
61 | return existProcesses.containsKey(name);
62 | }
63 |
64 | // 通过进程名称在existList里面找到进程,返回对进程的引用。若无,则返回null
65 | public Process findProcess(String processName) {
66 | for (Map.Entry entry : existProcesses.entrySet()) {
67 | String name = entry.getKey();
68 | if (processName.equals(name)) {
69 | return entry.getValue();
70 | }
71 | }
72 | return null;
73 | }
74 |
75 | // 进程调度
76 | public static void scheduler() {
77 | Process currentProcess = pcb.getCurrentProcess();
78 | Process readyProcess = readyQueue.getProcess();
79 | if (readyProcess == null) { // 就绪队列为空时,CPU正在运行的只有init进程
80 | pcb.getCurrentProcess().setState(Process.State.RUNNING);// 状态设为运行状态
81 | return;
82 | } else if (currentProcess == null) { // 实际上,此处只有在刚初始化系统时才可能发生
83 | readyQueue.removeProcess(readyProcess);
84 | pcb.setCurrentProcess(readyProcess);
85 | readyProcess.setState(Process.State.RUNNING);
86 | return;
87 | } else if (currentProcess.getState() == Process.State.BLOCKED || currentProcess.getState() == Process.State.TERMINATED) { //当前进程被阻塞或者已经被终止
88 | readyQueue.removeProcess(readyProcess); // 从就绪队列取出一个就绪进程
89 | pcb.setCurrentProcess(readyProcess); // 将该进程设为当前运行的进程
90 | readyProcess.setState(Process.State.RUNNING); // 该进程状态设为运行状态
91 | } else if (currentProcess.getState() == Process.State.RUNNING) { // 新创建了进程,或者阻塞队列中进程转移到readyList
92 | if (currentProcess.getPriority() < readyProcess.getPriority()) { // 若就绪进程优先级更高,则切换进程
93 | preempt(readyProcess, currentProcess);
94 | }
95 | } else if (currentProcess.getState() == Process.State.READY) { // 时间片完的情况
96 | if (currentProcess.getPriority() <= readyProcess.getPriority()) { // 若有优先级大于或等于当前进程的就绪进程,则切换进程
97 | preempt(readyProcess, currentProcess);
98 | } else { // 如果没有高优先级的就绪进程,则当前进程依然继续运行
99 | currentProcess.setState(Process.State.RUNNING);
100 | }
101 | }
102 | return;
103 | }
104 |
105 | // 进程切换
106 | public static void preempt(Process readyProcess, Process currentProcess) {
107 | if (exsitName(currentProcess.getProcessName())) {
108 | readyQueue.addProcess(currentProcess); // 将当前进程加入就绪队列中
109 | currentProcess.setState(Process.State.READY); // 将进程状态置为就绪状态
110 | readyQueue.removeProcess(readyProcess); // 从就绪队列取出一个就绪进程
111 | pcb.setCurrentProcess(readyProcess);// 将该进程设为当前运行的进程
112 | readyProcess.setState(Process.State.RUNNING);// 该进程状态设为运行状态
113 | return;
114 | }
115 | }
116 |
117 | // 时间片轮转(RR),时间片完后切换进程
118 | public static void timeout() {
119 | pcb.getCurrentProcess().setState(Process.State.READY); // 时间片完直接将当前运行进程置为就绪状态
120 | scheduler(); // 调度
121 | }
122 |
123 | // 从existProcess队列中删除进程
124 | public void killProcess(Process process) {
125 | String name = process.getProcessName();
126 | existProcesses.remove(name);
127 | }
128 |
129 | // 递归打印进程树信息
130 | public void printProcessTree(Process process, int retract) {
131 | for (int i = 0; i < retract; i++) {
132 | System.out.print(" ");
133 | }
134 | // System.out.println("|-" + process.getProcessName() + "(进程状态:" + process.getState() + ",优先级:" + process.getPriority() + ")");
135 | System.out.print("|-");
136 | printProcessDetail(process);
137 | List children = process.getChildren(); // 获取子进程
138 | for (int i = 0; i < children.size(); i++) {
139 | Process child = children.get(i);
140 | printProcessTree(child, retract + 1); // 递归打印子树的进程树信息
141 | }
142 | }
143 |
144 | // 输出进程的详细信息
145 | public void printProcessDetail(Process process) {
146 | System.out.print(process.getProcessName() + "(PID:" + process.getPID() + ",进程状态:" + process.getState() + ",优先级:" + process.getPriority() + ",");
147 | if (process.getResourceMap().isEmpty()) { // 判断有无资源占用
148 | System.out.println("(无资源占用))");
149 | } else {
150 | StringBuilder sb = new StringBuilder();
151 | sb.append("(");
152 | for (Map.Entry entry : process.getResourceMap().entrySet()) {
153 | Resource res = entry.getKey();
154 | int holdNum = entry.getValue();
155 | sb.append(",").append("R").append(res.getRID()).append(":").append(holdNum);
156 | }
157 | sb.append(")");
158 | String result = sb.toString();
159 | System.out.println(result.replaceFirst(",", ""));
160 | }
161 | }
162 |
163 | // // 打印existProcess的信息,主要是方便测试
164 | // public void printExistProcess() {
165 | // StringBuilder sb = new StringBuilder();
166 | // sb.append("existList:[");
167 | // for (Map.Entry entry : existProcesses.entrySet()) {
168 | // String name = entry.getKey();
169 | // String state = entry.getValue().getState().toString();
170 | // sb.append(",").append(name)
171 | // .append("(").append(state).append(")");
172 | // }
173 | // sb.append("]");
174 | // String result = sb.toString();
175 | // System.out.println(result.replaceFirst(",", ""));
176 | // }
177 |
178 | }
179 |
--------------------------------------------------------------------------------
/src/Process.java:
--------------------------------------------------------------------------------
1 | import java.util.List;
2 | import java.util.Map;
3 | import java.util.concurrent.ConcurrentHashMap;
4 |
5 | /**
6 | * 进程类,用于进程的定义和进程状态的管理
7 | */
8 | public class Process {
9 | private int PID; // 进程ID
10 | private String processName; // 进程名
11 | private int priority; // 进程优先级
12 | private State state; // 进程状态
13 | private ConcurrentHashMap resourceMap; // 进程持有的资源和相应数量
14 | private Resource blockResource;// 如果进程状态为阻塞的话,这个属性就指向被阻塞的资源,否则应该为null
15 |
16 | private Process parent; // 进程的父进程
17 | private List children; // 进程的子进程
18 |
19 | private static final PCB pcb = PCB.getPCB();
20 | private static final Queue readyQueue = Queue.getReadyQueue();
21 |
22 | // 进程的五状态:NEW(新建), READY(就绪),RUNNING(运行), BLOCKED(阻塞), TERMINATED(终止)
23 | public enum State {
24 | NEW, READY, RUNNING, BLOCKED, TERMINATED
25 | }
26 |
27 | public Process(int PID, String processName, int priority, State state, ConcurrentHashMap resourceMap, Process parent, List children) {
28 | this.PID = PID;
29 | this.processName = processName;
30 | this.priority = priority;
31 | this.state = state;
32 | this.resourceMap = resourceMap;
33 | this.parent = parent;
34 | this.children = children;
35 | }
36 |
37 | public int getPID() {
38 | return PID;
39 | }
40 |
41 | public String getProcessName() {
42 | return processName;
43 | }
44 |
45 | public int getPriority() {
46 | return priority;
47 | }
48 |
49 | public State getState() {
50 | return state;
51 | }
52 |
53 | public void setState(State state) {
54 | this.state = state;
55 | }
56 |
57 | public void setParent(Process parent) {
58 | this.parent = parent;
59 | }
60 |
61 | public List getChildren() {
62 | return children;
63 | }
64 |
65 |
66 | public Resource getBlockResource() {
67 | return blockResource;
68 | }
69 |
70 | public Map getResourceMap() {
71 | return resourceMap;
72 | }
73 |
74 | public void setBlockResource(Resource blockResource) {
75 | this.blockResource = blockResource;
76 | }
77 |
78 | // 删除进程时调用
79 | public void destroy() {
80 | killSubTree();
81 | PCB.scheduler();
82 | return;
83 | }
84 |
85 | // 删除子进程
86 | public void removeChild(Process process) {
87 | for (Process child : children) {
88 | if (child == process) {
89 | children.remove(child);
90 | return;
91 | }
92 | }
93 | }
94 |
95 | // 删除进程以及以其为根的进程树
96 | public void killSubTree() {
97 | if (!children.isEmpty()) { // 当进程子树不为空
98 | int childNum = children.size();
99 | for (int i = 0; i < childNum; i++) {
100 | Process child = children.get(0);
101 | child.killSubTree();// 递归删除子树
102 | }
103 | }
104 | // 对不同状态的进程处理
105 | if (this.getState() == State.TERMINATED) { // 进程状态已为终止状态,说明删除成功
106 | pcb.killProcess(this);
107 | return;
108 | } else if (this.getState() == State.READY) { // 进程状态为就绪状态,从就绪队列删除,修改其状态为终止状态
109 | readyQueue.removeProcess(this);
110 | pcb.killProcess(this);
111 | this.setState(State.TERMINATED);
112 | } else if (this.getState() == State.BLOCKED) { // 进程状态为阻塞状态,从阻塞队列删除,修改其状态为终止状态
113 | Resource blockResource = this.getBlockResource();
114 | blockResource.removeBlockProcess(this);
115 | pcb.killProcess(this);
116 | this.setState(State.TERMINATED);
117 | } else if (this.getState() == State.RUNNING) { // 进程状态为运行状态时直接终止,修改其状态为终止状态
118 | pcb.killProcess(this);
119 | this.setState(State.TERMINATED);
120 | }
121 | // 清除进程的parent和child指针
122 | parent.removeChild(this);
123 | parent = null;
124 | //释放资源
125 | for (Resource resource : resourceMap.keySet()) {
126 | resource.release(this);
127 | }
128 | return;
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/src/Queue.java:
--------------------------------------------------------------------------------
1 | import java.util.Deque;
2 | import java.util.LinkedList;
3 |
4 | /**
5 | * 队列类,用于管理与维护进程队列
6 | */
7 | public class Queue {
8 | private Deque[] deques;// 不同优先级就绪队列组成数组
9 | private static final Queue readyQueue = new Queue();// 单例设计模式-饿汉式
10 |
11 | private Queue() {
12 | deques = new LinkedList[3];
13 | for (int i = 0; i < 3; i++) { //进程有3种不同优先级,因此构造3个就绪队列
14 | deques[i] = new LinkedList<>();
15 | }
16 | }
17 |
18 | public static Queue getReadyQueue() {
19 | return readyQueue;
20 | }
21 |
22 | // 将进程加入到其对应优先级的就绪队列中
23 | public void addProcess(Process process) {
24 | int priority = process.getPriority();
25 | Deque deque = deques[priority];
26 | deque.addLast(process);
27 | }
28 |
29 | // 获得就绪队列里面优先级最高的进程。若队列为空,则返回null
30 | public Process getProcess() {
31 | for (int i = 2; i >= 0; i--) { // 因为是获取优先级最高的进程,因此应该按优先级从高到低遍历
32 | Deque deque = deques[i];
33 | if (!deque.isEmpty()) {
34 | return deque.peekFirst(); // 当队列不空时返回队列中第一个进程
35 | }
36 | }
37 | return null; // 若队列为空,则返回null
38 | }
39 |
40 | // 删除就绪队列里面指定的进程。删除成功返回true,若进程不存在就返回false。
41 | public boolean removeProcess(Process process) {
42 | int priority = process.getPriority();
43 | Deque deque = deques[priority];
44 | return deque.remove(process);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Resource.java:
--------------------------------------------------------------------------------
1 | import java.util.Deque;
2 | import java.util.LinkedList;
3 | import java.util.Map;
4 |
5 | /**
6 | * 资源类,用于资源的定义与资源管理
7 | */
8 | public class Resource {
9 | private int RID; //资源ID
10 | private int max; //分配的资源最大数量
11 | private int remaining; //剩余的资源数量
12 | private Deque blockDeque; //在该资源上阻塞的进程队列
13 |
14 | private static final PCB pcb = PCB.getPCB();
15 | private static final Queue readyQueue = Queue.getReadyQueue();
16 |
17 | // 阻塞进程
18 | class BlockProcess {
19 | private Process process;
20 | private int need; //需要请求的资源数量
21 |
22 | public BlockProcess(Process process, int need) {
23 | this.process = process;
24 | this.need = need;
25 | }
26 |
27 | public Process getProcess() {
28 | return process;
29 | }
30 |
31 |
32 | public int getNeed() {
33 | return need;
34 | }
35 |
36 | }
37 |
38 | public Resource(int RID, int max) {
39 | this.RID = RID;
40 | this.max = max;
41 | this.remaining = max;
42 | blockDeque = new LinkedList<>();
43 | }
44 |
45 | public int getRID() {
46 | return RID;
47 | }
48 |
49 | public void addRemaining(int num) {
50 | this.remaining += num;
51 | }
52 |
53 | // 在阻塞队列中直接删除指定进程,在终止进程时调用
54 | public boolean removeBlockProcess(Process process) {
55 | for (BlockProcess bProcess : blockDeque) {
56 | if (bProcess.getProcess() == process) {
57 | blockDeque.remove(bProcess);
58 | return true;
59 | }
60 | }
61 | return false;
62 | }
63 |
64 | // 进程请求资源
65 | public void request(Process process, int need) {
66 | if (need > max) { // 请求数量大于最大数量时申请失败
67 | System.out.println("请求资源失败!请求资源大于最大数量!");
68 | return;
69 | } else if (need > remaining && !"init".equals(process.getProcessName())) { // 对于非init进程需要阻塞
70 | blockDeque.addLast(new BlockProcess(process, need)); // 加入阻塞队列
71 | process.setState(Process.State.BLOCKED); // 设置进程为阻塞状态
72 | process.setBlockResource(this);
73 | PCB.scheduler(); //调度
74 | // System.out.println("资源申请失败,进程阻塞");
75 | return;
76 | } else if (need > remaining && "init".equals(process.getProcessName())) { //init进程不阻塞
77 | // System.out.println("资源申请失败,进程阻塞");
78 | return;
79 | } else { // 可正常分配资源
80 | remaining = remaining - need; // 剩余资源数量减少
81 | Map resourceMap = process.getResourceMap();
82 | if (resourceMap.containsKey(this)) {
83 | Integer alreadyNum = resourceMap.get(this);
84 | resourceMap.put(this, alreadyNum + need); // 已分配资源增加
85 | } else {
86 | resourceMap.put(this, need);
87 | }
88 | }
89 | }
90 |
91 | // 进程释放资源并唤醒阻塞进程
92 | public void release(Process process) {
93 | int num = 0;
94 | num = process.getResourceMap().remove(this);
95 | if (num == 0) {
96 | return;
97 | }
98 | remaining = remaining + num; // 释放资源
99 | while (!blockDeque.isEmpty()) {
100 | BlockProcess blockProcess = blockDeque.peekFirst();
101 | int need = blockProcess.getNeed();
102 | if (remaining >= need) { // 若剩余资源数量大于need,则可以唤醒阻塞队列队头的一个进程
103 | Process readyProcess = blockProcess.getProcess();// 从阻塞队列取出进程
104 | request(readyProcess, need); // 进程请求资源
105 | blockDeque.removeFirst(); // 从阻塞队列移除该进程
106 | readyQueue.addProcess(readyProcess); // 加入就绪队列
107 | readyProcess.setState(Process.State.READY); // 进程设为就绪状态
108 | readyProcess.setBlockResource(null); // 此时已没有被阻塞资源
109 | if (readyProcess.getPriority() > pcb.getCurrentProcess().getPriority()) { // 如果唤醒的进程优先级高于当前进程优先级则抢占执行
110 | pcb.preempt(readyProcess, pcb.getCurrentProcess());
111 | }
112 | } else {
113 | break;
114 | }
115 | }
116 | }
117 |
118 |
119 | // 进程释放资源并唤醒阻塞进程
120 | public void release(Process process, int num) {
121 | // if (num > process.getResourceMap().get(this)) {
122 | // System.out.println("错误!请输入合法的参数");
123 | // return;
124 | // }
125 | if (num == 0) {
126 | return;
127 | }
128 | // if (num == process.getResourceMap().get(this)) {
129 | // num = process.getResourceMap().remove(this);
130 | // }
131 | remaining = remaining + num; // 释放资源
132 | while (!blockDeque.isEmpty()) {
133 | BlockProcess blockProcess = blockDeque.peekFirst();
134 | int need = blockProcess.getNeed();
135 | if (remaining >= need) { // 若剩余资源数量大于need,则可以唤醒阻塞队列队头的一个进程
136 | Process readyProcess = blockProcess.getProcess();// 从阻塞队列取出进程
137 | request(readyProcess, need); // 进程请求资源
138 | blockDeque.removeFirst(); // 从阻塞队列移除该进程
139 | readyQueue.addProcess(readyProcess); // 加入就绪队列
140 | readyProcess.setState(Process.State.READY); // 进程设为就绪状态
141 | readyProcess.setBlockResource(null); // 此时已没有被阻塞资源
142 | if (readyProcess.getPriority() > pcb.getCurrentProcess().getPriority()) { // 如果唤醒的进程优先级高于当前进程优先级则抢占执行
143 | pcb.preempt(readyProcess, pcb.getCurrentProcess());
144 | }
145 | } else {
146 | break;
147 | }
148 | }
149 | }
150 |
151 | // 打印资源状态
152 | public void printCurrentStatus() {
153 | StringBuilder sb = new StringBuilder();
154 | sb.append("res-")
155 | .append(RID)
156 | .append("{max=")
157 | .append(max)
158 | .append(",remaining:")
159 | .append(remaining)
160 | .append(",")
161 | .append("blockDeque[");
162 | for (BlockProcess bProcess : blockDeque) {
163 | sb.append(",{")
164 | .append(bProcess.getProcess().getProcessName())
165 | .append(":")
166 | .append(bProcess.getNeed())
167 | .append("}");
168 | }
169 | sb.append("]}");
170 | String result = sb.toString();
171 | System.out.println(result.replace("[,", "["));
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/test/0.txt:
--------------------------------------------------------------------------------
1 | cr x 1
2 | cr p 1
3 | cr q 1
4 | cr r 1
5 | to
6 | req R2 1
7 | to
8 | req R3 3
9 | to
10 | req R4 3
11 | to
12 | to
13 | req R3 1
14 | req R4 2
15 | req R2 2
16 | to
17 | de q
18 | to
19 | to
--------------------------------------------------------------------------------
/test/1.txt:
--------------------------------------------------------------------------------
1 | cr A 1
2 | cr B 1
3 | cr C 1
4 | to
5 | cr D 1
6 | cr E 1
7 | to
8 | cr F 1
9 | req R1 1
10 | req R2 2
11 | to
12 | req R2 1
13 | req R3 3
14 | to
15 | req R4 4
16 | to
17 | req R3 2
18 | to
19 | rel R2 1
20 | to
21 | rel R3 2
22 | to
23 | to
24 | req R3 3
25 | de B
26 | to
27 | to
28 | to
--------------------------------------------------------------------------------
/test/2.txt:
--------------------------------------------------------------------------------
1 | cr A 1
2 | cr B 1
3 | cr C 1
4 | req R1 1
5 | to
6 | cr D 1
7 | req R2 2
8 | cr E 2
9 | req R2 1
10 | to
11 | to
12 | to
13 | rel R2 1
14 | de B
15 | to
16 | to
--------------------------------------------------------------------------------
/test/3.txt:
--------------------------------------------------------------------------------
1 | cr A 1
2 | cr B 1
3 | cr C 1
4 | to
5 | cr D 1
6 | cr E 1
7 | cr F 1
8 | to
9 | to
10 | to
11 | req R1 1
12 | req R2 1
13 | to
14 | req R2 1
15 | to
16 | req R3 3
17 | req R4 3
18 | req R4 3
19 | to
20 | req R1 1
21 | cr G 2
22 | req R1 1
23 | de B
24 | req R3 2
25 | cr H 2
26 | cr I 2
27 | to
28 | req R3 3
29 | req R3 2
30 | to
31 | rel R3 1
32 | to
--------------------------------------------------------------------------------
/test/4.txt:
--------------------------------------------------------------------------------
1 | cr x 1
2 | cr p 1
3 | cr q 1
4 | cr r 1
5 | to
6 | to
7 | to
8 | req R1 1
9 | to
10 | req R2 1
11 | to
12 | req R3 2
13 | to
14 | to
15 | rel R1 1
16 | to
17 | req R3 3
18 | de p
19 | to
--------------------------------------------------------------------------------
/test/5.txt:
--------------------------------------------------------------------------------
1 | cr a 1
2 | cr b 1
3 | cr c 1
4 | cr d 1
5 | to
6 | cr f 1
7 | req R1 1
8 | to
9 | to
10 | to
11 | cr e 2
12 | req R1 1
13 | to
14 | de b
15 | req R1 1
16 | to
17 | to
18 | to
19 | to
20 | to
--------------------------------------------------------------------------------
/test/OSLab1-Scheduler.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eternity-Myth/Operating-System-Experiment/3bcd08379ed723a3958d685ffbf37d790640a8a8/test/OSLab1-Scheduler.jar
--------------------------------------------------------------------------------
/test/README.md:
--------------------------------------------------------------------------------
1 | 测试文件与测试用例
2 |
3 | ## 使用
4 |
5 | 编辑修改批处理文件中的文件名,运行批处理文件(需要本机配置好Java环境)
6 |
7 | ## 鸣谢
8 |
9 | [同学们提供的测试用例若干](https://github.com/502408764/os-test-shell)
10 |
--------------------------------------------------------------------------------
/test/读取文件模式.bat:
--------------------------------------------------------------------------------
1 | java -jar OSLab1-Scheduler.jar *.txt
2 | pause
--------------------------------------------------------------------------------
/test/键盘录入模式.bat:
--------------------------------------------------------------------------------
1 | java -jar OSLab1-Scheduler.jar
2 |
--------------------------------------------------------------------------------
/关文聪 2016060601008 计算机操作系统 实验报告.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eternity-Myth/Operating-System-Experiment/3bcd08379ed723a3958d685ffbf37d790640a8a8/关文聪 2016060601008 计算机操作系统 实验报告.docx
--------------------------------------------------------------------------------
/关文聪 2016060601008 计算机操作系统 实验报告.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eternity-Myth/Operating-System-Experiment/3bcd08379ed723a3958d685ffbf37d790640a8a8/关文聪 2016060601008 计算机操作系统 实验报告.pdf
--------------------------------------------------------------------------------
/实验报告模板.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Eternity-Myth/Operating-System-Experiment/3bcd08379ed723a3958d685ffbf37d790640a8a8/实验报告模板.docx
--------------------------------------------------------------------------------