% e! w- g" I: f' j* }四、设计思想 ! e E4 i* A; d7 H& |: `* M, d. j4.1 设计思路 0 l4 z. h' e' g* g& O1 I1 t5 P6 G 对于单道批处理系统,由于在单道批处理系统中,作业一投入运行,它就占有计算机的一切资源直到作业完成为止,因此调度作业时不必考虑它所需要的资源是否得到满足,它所占用的 CPU时限等因素。, |, K4 H) q% z# q* J
作业调度算法:采用先来先服务(FCFS)调度算法,即按作业提交的先后次序进行调度。总是首先调度在系统中等待时间最长的作业。每个作业由一个作业控制块JCB表示,JCB可以包含如下信息:作业名、提交时间、所需的运行时间、所需的资源、作业状态、链指针等等。3 N- A _9 v1 ?" B' S! [3 d
作业的状态可以是等待W(Wait)、运行R(Run)和完成F(Finish)三种状态之一。每个作业的最初状态总是等待W。各个等待的作业按照提交时刻的先后次序排队,总是首先调度等待队列中队首的作业。每个作业完成后要打印该作业的开始运行时刻、完成时刻、周转时间和带权周转时间,这一组作业完成后要计算并打印这组作业的平均周转时间、带权平均周转时间。7 B% Q9 r& E, d) S3 h0 v3 [
而对于多道批处理系统来说,作业调度(响应比)按一定的算法从磁盘上的“输入井”中选择资源能得到满足的作业装入内存,使作业有机会去占用处理器执行。但是,一个作业能否占用处理器,什么时间能够占用处理器,必须由进程调度来决定。所以,作业调度选中 了一个作业且把它装入内存时,就应为该作业创建一个进程,若有多个作业被装入内存,则内存中同时存在多个进程,这些进程的初始状态为就绪状态,然后,由进程调度(优先数)来选择当前可占用处理器的进程,进程运行中由于某种原因状态发生变化,当它让出处理器时,进程调度就再选另一个作业的进程运行。 因此,作业调度与进程调度相互配合才能实现多道作业的并行执行。+ M: O% u& a* m; e9 j+ V
$ E' v. a1 Z: ]8 _2 n4 K
4.2 单道批处理系统( R- i; ]9 s1 I" \9 [( [+ E2 E; c" I
4.2.1 代码结构 3 _7 y/ S& R! Z& q% }7 W 因为这里的单道批处理系统需要实现多种算法,因此使用了 模板方法设计模式 + 策略模式 来进行开发,下面为各种算法的类签名,算法的具体实现可见代码实现。 7 ]& }& l( \; t/ S3 z j 5 h6 N( G- c+ a9 o0 h/* 单道批处理系统基类 */% A* w" [# _( i5 X: B/ `* C
class SchedulingAlgorithm;1 C8 G' S0 q8 F0 o0 A# C
& s- r7 k& q; m$ a7 I2 C
/* First-Come First-Served 先来先服务算法 */ $ C9 Z+ t- j) h$ q5 O: y! ]class FCFSSchedulingAlgorithm : public SchedulingAlgorithm; , R0 S4 r* \1 G9 d. I7 Y2 P$ y5 W7 C& P# m( e- L4 ]$ \
/* Short Job First 短作业优先算法 */6 h$ Y- Y; b% N0 o, M
class SJFSchedulingAlgorithm : public SchedulingAlgorithm;: G$ R; x0 u/ v5 y; ^& t
/ t8 x9 U8 l# z5 p) ^1 @ {
/* Highest Response Ratio Next 高响应比优先算法 */ % u, z$ P/ e% c- I3 }% Fclass HRRNSchedulingAlgorithm : public SchedulingAlgorithm; % g0 i5 m- \% X19 A8 Y# Q2 `. e7 c( C* n8 h
2 7 h7 y$ J5 @ Q( H* r+ }' @3% c4 s+ @. @! d0 n. B+ ?
4- ? G/ \' T# W A
5 1 j9 C0 Q$ O ~5 d0 V8 s67 V. P9 A% F3 B) c" _! L
7 , S6 @' O7 G8 e: \4 n8 d, d& S* p1 V5 E3 |
9 ( j3 d8 I/ Z7 B, d, o4 m9 _10 % U' _8 i. L! p4 D9 Q* d11 & K" F0 ~6 n) v0 w9 o* \4.2.2 FCFS3 A! l5 |, u- i! |- Z8 S) X8 \, c5 f
因为这里使用优先级队列来实现,所以我们只需要为每种算法定义不同的比较函数即可,比如对于FCFS算法来说,它的比较算法就是比较该作业提交的时间。1 a' t* I3 x' I- I# ]
+ F7 w2 x3 \7 m3 L, R// First-Come First-Served 7 j" `$ g) C: X$ G+ @class FCFSSchedulingAlgorithm : public SchedulingAlgorithm; M0 S/ V- s) y" ^& U' C& |
{2 S% _, F. G6 H. l) E; O4 S
public: ( Q9 w+ e& @3 [9 M struct PriorityCmp( @* A+ t; @5 T. J) L
{8 L4 E' Q' v: P& K8 _
bool operator()(const JCB j1, const JCB j2) 4 J4 u4 b9 |5 H& Q* k {8 |% x4 |* K& A
return j1.submit_time > j2.submit_time; 6 O$ b. U* S' I }( P8 a0 Q- U) D- l/ v
}; * c3 X+ e' H3 f4 K2 ]- W + k4 ~* N ]* i. T8 ^ FCFSSchedulingAlgorithm(){} # ^! e/ @. D- e) Z4 V& z& X. a};! X7 C4 s# k% a# a6 F0 Z6 Q& s
1 5 ~ G/ H- ]5 d( s" w2 x2 k: f2 8 i! ^$ m* w* S- V W# A+ g32 }0 q8 K/ N# k
4; [) `0 }$ K* D* S* m+ K+ y
5 ( o. ]1 ~ c' m6 7 O! z2 p( g4 u- C7' u# ]: |: c/ {7 o0 L
81 C' Q4 i( O: o1 s8 \6 n6 U1 L6 j. t
9 2 A! n1 a2 a1 J8 j) x# I104 d+ ~4 b7 o1 U
11 $ v, ~! t" L; t( B/ t' r1 q* [7 [12 ( }5 m% n1 P6 e131 a) F7 b( @% E8 K [' n: |
14; P" U, i% a: k9 I6 i7 b$ Q1 U5 F
4.2.3 SJF * G7 P, d+ \; C p+ s 对于SJF算法来说,它的比较函数就是比较作业的时间长度(时间越短优先级越高)。& @! X9 ~! v m+ x" l4 r
: _8 Y$ l5 h) Q2 n
// Short Job First) z/ ~0 L& z9 \% T$ ^! H* \
class SJFSchedulingAlgorithm : public SchedulingAlgorithm 4 g- g$ ~0 U; G' ]$ ~, h{ 6 h) _7 a7 ?, F0 Upublic:& W- v% k1 N6 [3 R2 a9 |5 }) b
struct PriorityCmp u4 K# t" Y- \: U( l
{# H4 ?2 w# ?6 F! i: ]1 t7 B
bool operator()(const JCB j1, const JCB j2)( r' ]* v! [( x; f2 G
{0 m) l8 k0 F9 _! \5 P
return j1.required_running_time > j2.required_running_time; ' T1 Y4 d" a$ K" a% n/ y }, E+ x# e/ {, i+ j0 ]
}; ( S# u4 @6 W3 Y" i, O: M6 I3 R% i6 a# C5 z
SJFSchedulingAlgorithm(){}$ s! G ?' R' M' J- h7 N
}; - I/ H) W* o& X5 {8 E& l1 ) ]+ o/ {5 L. g, n2# U4 G( }8 T& z' K* b! K+ O6 K5 D
3 4 Q) B7 Y( n, f7 U* E$ y* n8 C u4. m2 \3 u s5 t
5 & s; P0 |( o; }1 j6# ~/ A1 H( E0 p) `. j% ]
7% Y1 z1 e) t& O C: b
87 m! }7 r7 J8 u
9+ H" W6 K" V0 b; t+ \
10 1 I1 @- U0 x; l, I/ x! G' }6 l11. |2 |# }2 h3 D3 D: a
12 - _% \: } S0 I4 K6 h13 n0 e( k; V1 v: |14 ( U! N( A. n6 H% S4.2.4 HRRN ' |+ { p |' E, q# Q$ d 该算法的比较函数比较的是每个作业的响应比:(等待时间+要求服务时间)/要求服务时间,响应比越高,优先级越高,越优先被调度。! r8 k# o: T3 |
2 d5 _, Y: M1 B
// Highest Response Ratio Next 9 p& u2 Y" o0 ?, p8 W/ h$ }class HRRNSchedulingAlgorithm : public SchedulingAlgorithm 0 z" d5 i8 \# _* l9 J1 n; U{ 6 H; l" \: A6 T$ Qpublic: ( U" H' l/ V' e" b3 a7 o struct PriorityCmp 0 V# A7 w t$ G! H& n" H {0 R- R4 Z- g4 @" w7 p& A6 e
double getPriority(JCB jcb) 1 Q6 i% ?& R" B6 y6 g4 [$ U {+ B+ S0 ^8 }0 f9 g' F4 T1 ~, y
return ((cur_time - jcb.submit_time) + jcb.required_running_time) / jcb.required_running_time; ! i+ s- l; j8 L! V% F } - q* Z1 d1 X4 A: g- d3 ^ + P u( h7 x: y" | Z8 ]( {7 |* l, b bool operator()(const JCB j1, const JCB j2) $ N( u% T* d* W2 r6 n { 7 `3 S6 r& E9 P" H9 }! k$ a return getPriority(j1) > getPriority(j2); `5 \1 v, R7 f Z8 b } ' l1 k2 @3 v( ~; V& q }; % U9 q% u3 q/ x" ?& v, c # b+ e8 F! c! [2 ~- P/ _6 T HRRNSchedulingAlgorithm(){} 2 s0 y. O& j% H: f9 h};6 u7 u) N+ _, u5 p8 }% S
1 , @! v( p: l9 X; H2& c/ T; n1 E X6 U
3 9 q1 ]# Z+ p, p4 ; w6 s( u. n, g0 a, w; g. o5 " b6 |3 C( P- P( v1 e6( y+ E1 v. Z. f% B8 v7 l# P: C. Q
7* J- U2 E. G. g& |! r" h% B: b
8 5 ` Z! D; [4 L; \90 l& |/ {% b- q6 }' O! T7 w. M5 k
10# w+ _; ]2 E$ p
11; L5 L0 v* O8 B; `( ], O9 D9 q
12( n4 E( n G9 X( Q, [6 s
13. ~# B6 H: S- N4 N
14 * R! w- ` Y9 S1 e# b( f15* g$ c5 E! C) V2 f
16 4 y* Z, d0 ^ u$ i! @3 S: j4 j# @& u17 ' n* G/ g3 V7 f/ V T18 ; N/ K4 `/ P- m- t3 |1 Q7 U9 _19 ) i2 j) M+ _' C4.3 多道批处理系统 2 a8 V# F& y! _3 j3 ~4.3.1 FCFS + PSA# O( z6 x2 }5 b; d9 x& I* E
对于多道批处理系统来说,情况会复杂一些,因为对于多道批处理系统,除了作业的调度还存在进程的调度,也就是作业调度决定该任务能不能使用处理机(有没有资格),但就算该任务被调度了,因为多道批处理系统,还需要考虑相关的资源,因此能不能使用到处理机,还要看进程的调度。 * V9 r# D; g; {' V 因此在这里对于作业调度采用了FCFS算法,而对于进程的调度采用了PSA算法(静态优先级,可抢占),并且没有继续使用实验一中的进程调度算法的代码,而是重新写了一遍。 " l& ~% i1 p8 N0 e 所有的任务初始会被存放在 back_queue 中,而就绪的任务和正在运行的任务都存储于 psa_ready_queue 中,等到 psa_ready_queue 中存在空间时,会通过任务调度算法从 back_queue 中选择合适的任务进行调度,当任务(准确说是进程)被调到 psa_ready_queue 中后,会根据它的优先级判断它是否能够优先运行,如果不能就只能保持就绪状态,一直等到优先级高的进程运行完毕后再运行。, ^: x. Q8 l% A u, |, u
因为这部分代码的逻辑比较复杂,所以就不在这里单独罗列了,具体可见下面的代码实现。需要注意的是多道批处理系统代码逻辑中被注释掉的代码为测试代码,可以使用其来对代码的准确性进行测试。 3 Y. J8 d( E6 {1 D2 A M/ K0 g9 @+ ]" X9 o
五、代码实现% ]* Y& t/ G1 _9 y' B
#include <iostream>( x8 m/ C0 b+ x
#include <string> " a8 u- q. [/ |#include <vector>- P X5 N Q% E! v$ o& Q% D
#include <queue>; N+ {7 u% a/ ^- {: Q
#include <cstdlib> " @2 a E5 R/ H6 O9 a' r/ O2 S6 ]#include <ctime>3 v4 {# ]! c2 e, s+ @" M8 D' L
#include <unistd.h>8 I5 G+ ?9 w x7 G( W4 `2 _
#include <iomanip>$ C( @; ^3 P# ~. M" s3 ^& @
7 A {% }$ V, otypedef int TimeSlice; ) t; O" A/ D: {4 Rtypedef int Resource; 8 [( h0 r1 d" l( M' Ntypedef std::queue<TimeSlice> * JobTimeSeries; ( X& o( }5 _; j b4 Y; W0 Z) O! J/ M
TimeSlice cur_time = 0; & t. m: j* K& W% L% U' K3 @int average_turnaround_time = 0; 8 d8 L/ G( e0 O/ @2 e# D" wdouble average_power_turnaround_time = 0; P# ]. Q1 W1 N e
. ?# ~$ ?9 k: R7 o; m/ `8 z' I
enum ProcessStatus+ ]' l5 n9 P% M" B! y3 M- A$ D
{0 D; e5 M. z7 ]
Ready = 0,4 o& D4 F7 X+ ]" n V J* p1 F
Running = 1, 1 x! b. t+ E( D$ g //Finish = 26 @- R2 h* b5 j7 G" J
}; }# k# n0 e. V& R $ w! ^7 Z, w/ h8 b9 btypedef int Pid;- V& E/ k# `# a4 S" |) c
typedef int TimeSlice;8 b& Y' ]% L2 R
typedef int Priority;4 ~: P* ~2 S6 n
/ M% d. q4 F$ [) K. D' ostruct JCB;$ n* c" d! I2 K3 u/ e' B
typedef JCB * JCBptr; & H5 l0 l8 b# }- m/ G # B0 w& e$ d, T' t& ` z+ ^, pstruct PCB& F; O1 n& c% L% O: o9 E2 j
{ . F: v! d! ]8 i3 w. v! h PCB(JCBptr jcb_) : jcb(jcb_){}+ D" t6 k) l5 h, b. j
Pid pid;7 w9 r2 L ?) F! }! u& |
ProcessStatus status;+ c1 t0 J' g7 O
Priority priority; 3 }; K8 G- F; j* k) y. L JCBptr jcb; x- b9 M+ v! s) H
}; & k$ t8 V: T& o7 s/ v" i : G; E- Q' ]# _$ g6 Q; ltypedef PCB * PCBptr;+ w! ~8 V4 v9 `) Z+ B* d2 N- [
7 Z; q7 X" ?$ ?$ G# x% Nenum JobStatus) l h5 u0 g7 |, ~0 W! Y
{; R' ? ]6 u* Y4 X9 u
Wait = 0,2 v/ G4 O9 \$ m3 c; g
Run = 1, - r4 S4 X7 ~) v0 Y' x/ {( r Finish = 2; h$ P, W# j, e( p/ {
}; W. P$ ]9 y: U S
7 k. \- G- M- c
struct JCB$ y' n, z& J6 B6 v2 l* d
{. ^ `4 x" z2 x8 p9 K( }
std::string job_name; * {, s/ Z/ k6 |! H2 u- J) ]( s9 G TimeSlice submit_time;5 U+ ]$ U0 ]2 Y2 A3 B. v+ g
TimeSlice required_running_time;4 L l' ~1 @+ l2 H9 `
9 l' e! h6 S/ r9 G4 z! Q
TimeSlice start_time = -1; $ B. @" J! m& J/ s6 c7 @ TimeSlice finish_time = 0; . x& R" N" T+ w0 L9 V" _ TimeSlice already_run_time = 0;9 @6 U. W: m* z7 J
' ~4 }8 z' x7 ]9 k/ G Resource required_resource;, n% M* Q, d2 C2 T3 i
JobStatus job_status;3 P; v4 H! l3 C5 H% k
PCBptr pcb = new PCB(this); , Z: I) X' }$ G3 h! W8 |4 a}; 2 t, [& @/ e _: f$ R* K& r; D6 V) Q# u% D
6 g9 h* J$ k+ N: k" {class Util, ~1 \4 ], g# C$ b8 @4 J
{; W! r3 ]% M9 ~+ S9 d5 x
public: & R: P, L3 J; q$ M7 f9 r static inline int getRandom(const int min_val, const int max_val, int match)* X+ @& @2 x4 X( [/ B
{ $ u' x5 V" H [( Q srand(time(0) + match); ; L& t% t7 G; r" I. H return rand() % (max_val - min_val - 1) + min_val; 1 e. t$ @# r8 ]) Z8 ` } 9 l9 n$ Q& ]3 k. R! F' J. Y& C0 w) R: v3 v9 Q5 v* _" K
static inline bool printJobData(const JCB jcb) 0 M$ X, w* X! p" N( H {% f" w$ ^* f3 r$ y) b1 e1 ?
TimeSlice start_time = cur_time; 7 V6 s4 D) p" E; L TimeSlice finish_time = start_time + jcb.required_running_time; 7 ]: y6 O8 V2 ?5 n" y% p: T TimeSlice turnaround_time = finish_time - jcb.submit_time; 6 A9 j& } B7 z double power_turnaround_time = turnaround_time / (jcb.required_running_time / 1.0); 8 b2 Y- H; I3 g8 \2 `7 X5 X8 @, S0 q j9 v P
std::cout << "[Data] " << jcb.job_name << " " / t0 w; a2 d% j1 o+ P! A. k << " Start time: " << start_time << " "' M, M( \. H* @
<< " Finish time: " << finish_time << " "* Q4 ?2 ~* i. E6 R/ [
<< " Turnaround time: " << turnaround_time << " " $ z- U8 ]4 u3 `1 B8 e << " Power turnaround time: " << std::setprecision(2) << power_turnaround_time << std::endl; _' }3 V. d3 ^: a2 L8 w: F
5 X. {3 F. w. _1 P8 X$ ?( V
_8 q0 k! _ A2 n: X" X2 X- A
average_turnaround_time += turnaround_time; 1 Z4 a, q% t8 s' T! E" {6 ]9 }5 T average_power_turnaround_time += power_turnaround_time; 6 ~7 P/ e* F9 l* v- _* C2 c' b! x; b* J5 k- |- A
return true; + R9 B8 e7 ]$ O7 E# `, g }. U9 p6 }( {! ^: {" L
8 b s# T# P# h S
static inline bool printJobData(const JCB jcb, bool isMul) 8 ]9 c8 d; V2 F q& ~8 D { , ~$ Q( F+ B. z2 w1 ? TimeSlice turnaround_time = jcb.finish_time - jcb.submit_time;3 W& D# f. J# C2 H$ ]2 g! c& M( D
double power_turnaround_time = turnaround_time / (jcb.required_running_time / 1.0);3 a4 a7 L+ ?& u% i
- \# \, l- h3 q3 h5 y" o$ Z* S
std::cout << "[Data] " << jcb.job_name << " " 2 P: F n) V+ m; } << " Finish time: " << jcb.finish_time << " " 9 K) c6 G. n( r5 d. P << " Turnaround time: " << turnaround_time << " " k& S. \4 J# Z9 b$ x
<< " Power turnaround time: " << std::setprecision(2) << power_turnaround_time << std::endl;3 F; R+ }7 ? [ ], y# D( q. `" w G
: G2 z# t( G/ `4 D" z& }6 Q; a2 |4 y3 Y5 c5 X% C; H
average_turnaround_time += turnaround_time; ) ?& s# ` E, G: f$ J average_power_turnaround_time += power_turnaround_time;5 K0 {' L3 u( M0 L
2 x! I5 U# I% z+ g
return true;# l9 g6 N3 X+ {* E- ]. _' a8 l* z% o
}7 f9 _- I+ p1 L- f9 d8 B
}; - J( L7 L2 | v0 ^, B8 b* _) e" F - h7 J* W/ c' o1 v) uclass SchedulingAlgorithm / ~, p; ^; E- y7 t7 Y; [{ $ }7 W7 x6 l* K% N7 ^. g4 ]public: $ t) ]) W4 X2 u+ P N5 U, \! D6 T @7 d9 M9 s( {8 J+ {' @
// virtual bool initPCB(std::priority_queue<JCB, std::vector<JCB>, std::less<JCB>> * ready_queue, int process_num) = 0; * h6 d" G2 m7 j' h1 m' M// virtual bool processPCB(JCB & pcb) = 0;5 Y& B" d; c$ F# u3 Q; l7 D6 o- Y
};0 H# w1 z- Y* \6 h& i
/ }) Y* D8 C7 T" B: y
// First-Come First-Served : T9 G& G! C$ J5 d2 n7 p/ d) R9 Qclass FCFSSchedulingAlgorithm : public SchedulingAlgorithm+ \& O6 o$ G+ s2 H; e% D' U
{ 8 D- U* S, [7 Dpublic:7 e; P: N% E6 f
struct PriorityCmp " L. n6 r, J4 [0 T& z {5 A2 R, }6 V3 `) P! d) Z) q
bool operator()(const JCB j1, const JCB j2)5 d t/ l; e' c f# K) }
{& W" }; U& x" F0 C' ?! D0 f
return j1.submit_time > j2.submit_time; r2 F& ~" R" g
} ; P. Y2 C& f1 m0 ^. e" j }; 4 {* j$ F# [2 {0 L# X6 G 2 M/ T2 Z0 T1 O [3 Q' i FCFSSchedulingAlgorithm(): V' ~, Y' P3 J3 M! |( [
{} ; h8 `3 u: @9 L + l, S$ d! e, Y, Eprivate:8 M& P; t+ [8 b3 R: t
1 Y6 f+ W9 H8 E, E' Y+ j# t( y6 v) q7 ~6 m: b$ j1 i& G' }
};4 O0 k+ ?; M- A) Z0 t' R- v" M: s
" c" F8 Y- K, |$ A# p$ m; S// Short Job First $ k& @2 N+ t) h M* F' t: aclass SJFSchedulingAlgorithm : public SchedulingAlgorithm 3 Q9 r6 ^* N' ~1 q: g{ 3 o, Y% S. Z& ^public: 0 z( I3 G# t, e) o( w struct PriorityCmp3 X% O- o& {8 X
{2 h+ F P0 h3 s4 z, l- E
bool operator()(const JCB j1, const JCB j2)% O. C% F& d/ f& o
{6 J$ B2 s3 b1 x6 n
return j1.required_running_time > j2.required_running_time; ! f# g6 `9 f; g }* D5 m O. E M8 g e$ ^
};' \3 q- n! a, U5 F$ Z
. H. t" k" c0 g3 P; Z SJFSchedulingAlgorithm() $ h) x) b, P5 L {} : W+ R( R: m1 _( X" P6 _& w) s# o+ [) M! N
}; 4 b6 r2 x, \, R1 L8 e2 C& R( r. _+ v
// Highest Response Ratio Next: q, R; q3 Z$ h7 ^# W
class HRRNSchedulingAlgorithm : public SchedulingAlgorithm , o' t |, ^! G{ ) v8 r! k( {; J" N5 Wpublic:* ^ g3 Q# i/ S
struct PriorityCmp . |% Q( F$ \7 l$ r+ X { ) l) e+ D2 y6 u4 V double getPriority(JCB jcb)6 s- N" M0 F$ n& y! U1 n6 U$ r
{- j+ x1 {' E X' G- q9 u4 N* W' d; @
return ((cur_time - jcb.submit_time) + jcb.required_running_time) / jcb.required_running_time; $ M0 D7 N: D- T3 O$ h3 h } , W" M5 P3 p3 S6 O. s2 z# ^: V / N( G. [1 u6 c5 P. _1 \) K bool operator()(const JCB j1, const JCB j2)9 v& L! }& j- @
{ / W9 f! P5 l, Y% x return getPriority(j1) > getPriority(j2); n* L% M8 V! {$ x. ]3 }+ J }5 _# P- w+ v# ?% ]7 z: u
}; + F1 Y2 {& @6 c$ @' m. f p* ?( s) z7 O# I) Q5 X6 T
HRRNSchedulingAlgorithm() . p# L: |! `# C6 v6 V% O {}1 i* z4 T3 z* l# S3 a$ e
};) b, s; f/ P" S& T, u- n; T7 ^
+ P+ I: z/ F* s/ W% r* {1 w5 V
template<typename PriorityCmp>4 Q# R. f, V$ h2 p7 K
class JobScheduling) c, r9 T9 E7 N( k
{ ; N/ d( K- `; `$ |, dpublic:+ x6 V4 S& N8 z6 ~ y
JobScheduling(int job_num) 5 T/ I% W0 g6 F b J% K$ a# f: a- V {. ^6 W9 a. T0 }
job_num_ = job_num;' `$ o6 j: ~4 H s* c2 N! G$ }
sa_ = new SchedulingAlgorithm(); 0 I& E+ V) }. I3 _4 E4 [0 y3 [5 T wait_queue_ = new std::priority_queue<JCB, std::vector<JCB>, PriorityCmp>();- D N; [* _# }2 X" \$ V
mock_jcbs_ = new std::priority_queue<JCB, std::vector<JCB>, PriorityCmpForMock>();, e: B4 `% I+ s6 {( H" c& m
finish_queue_ = new std::queue<JCB>();" y* s0 [: G! k) H/ q
! R7 s2 ~ V! Q( k% x& w3 E mockJCBs();; @9 {2 h2 \: W+ ^' }. [
} . h' v2 E7 J" ^6 Z: H Q- N; n, v2 d" ]' v2 M% L3 Yprotected:. R. h l8 P5 ~! z
struct PriorityCmpForMock# G) ^% E B* v) E
{ / u8 Q9 ^, }9 c! X8 [ bool operator()(const JCB j1, const JCB j2)/ r9 p; E1 p3 N% ] q5 A% S* y
{ ! I5 I' R6 O3 i$ M2 g return j1.submit_time > j2.submit_time;* g% c4 V) K0 t7 \7 k
} Z7 d" W$ X. W+ t$ ?2 B
};+ p$ p- w; M3 p/ Y+ Y" M5 v8 `+ K: i
4 M$ j+ E, Q8 e bool mockJCBs() ) Q7 W$ A5 _6 _1 v1 Q/ m- B { . p3 l- {3 B/ _ s4 O$ E for (int i = 0; i < job_num_; ++i)8 l# H6 D8 @/ G! f# l
{, \; k- Y8 x( a
JCBptr jcb = new JCB(); e" z) M8 m" e1 Q jcb->job_name = "job" + std::to_string(i); 0 d. \+ _, ^3 w6 J! D jcb->job_status = Wait;- `, [$ d$ \' Y- l9 h8 P
jcb->submit_time = Util::getRandom(1, 20, i); ' L1 e* P b) D2 @3 G2 r& {, n& s! \ // The minimum value is 3 so that each segment can be divided into time slice 4 M3 D& x+ K+ d- _ jcb->required_running_time = Util::getRandom(3, 10, i); ^% G; g. W1 D) `$ X6 U" [! ^2 G* P. d: p8 ~+ {* P
mock_jcbs_->push(*jcb); . j+ \+ h* P7 M4 t6 {4 q std::cout << "[INFO] finish init " << jcb->job_name << " with "6 H( T6 f D( l) P3 i8 {
<< " submit_time " << jcb->submit_time % r/ b( `) L% q6 | << " required_running_time " << jcb->required_running_time << std::endl; I# v' j& s; o. a }) z6 m# z/ k6 P( \
} ^0 k( J% @7 _8 h' c+ b: x7 e
: j- [& E+ F2 [& ]" ~ void getCurrentReadyQueue()/ Y1 S4 P; }% g& C& }+ V) b4 s
{ + H4 m0 N! ?* m while (!wait_queue_->empty())+ O! L0 H Q. n# e
{) a4 j7 _) r, e7 Z
JCB jcb = wait_queue_->top(); N. Q0 E5 ~0 b' j5 K2 r std::cout << jcb.submit_time << std::endl;7 n8 G/ ^. e1 d) I/ Q, F
wait_queue_->pop();' L- p' `! T2 u
} ; h/ i u6 W$ \4 F, P' M4 { } 7 P& m5 j% v* R/ ?; O: o0 q0 Z " |( h* v+ z( I% N9 R. j int job_num_; 2 x7 b+ k/ I( S+ [2 c$ M( e2 ` SchedulingAlgorithm* sa_; 0 a0 B5 a+ n) f% u2 A! H1 F/ Y std::priority_queue<JCB, std::vector<JCB>, PriorityCmpForMock>* mock_jcbs_; 2 }/ }' R: v6 c, h std::priority_queue<JCB, std::vector<JCB>, PriorityCmp>* wait_queue_; % N: }9 G+ }) ~ g std::queue<JCB>* finish_queue_;0 Z. c6 r2 ^. z, j4 r/ I4 H/ Z
}; 4 }9 z" |6 }; F: \% ^ " t, x- c4 h9 B4 e3 M6 atemplate<typename SchedulingAlgorithm, typename PriorityCmp> * r5 o( h- Z( }+ K' bclass SimpleBatchProcessingSystemJobScheduling : JobScheduling<PriorityCmp>7 C |9 }( a& {: v; E" t
{ 3 p0 @' z; e+ x0 P1 q4 Z8 W/ Ypublic:7 b) n: m ~3 C8 C: d2 B
SimpleBatchProcessingSystemJobScheduling(int job_num)3 Z6 K+ {) Q6 X8 ~
: JobScheduling<PriorityCmp>(job_num) - H) Z+ b3 `" F6 X, J {}; T& J' h+ T) i7 r0 [# D
% Z( \3 s/ U" V) i! l' H5 h/ [
bool start() 1 l, J1 O7 |, k! ]& [! Y) O8 B C { : A+ @+ x4 O7 i7 ~; s2 N; { cur_time = this->mock_jcbs_->top().submit_time;2 |+ c0 V& d- ~& V9 H( L0 r
while (!this->wait_queue_->empty() || !this->mock_jcbs_->empty()) - H X& U. B) d { ' F( z! [5 v; Z! Z3 u& f' m // Simulate adding tasks dynamically * ~2 V/ C4 X, r+ w9 u# N A/ b if (!this->mock_jcbs_->empty() && this->mock_jcbs_->top().submit_time <= cur_time)9 V9 }1 k6 y, l9 Z/ V
{ $ [: j3 v- b- J) T3 x JCB jcb = this->mock_jcbs_->top(); 5 }" ~7 l$ A( n. G, o7 N( w7 ]9 t4 @: @ this->mock_jcbs_->pop();6 N8 a0 ]+ T- k
0 A3 n6 k: g' U6 ]) K' v/ P* T
std::cout << "[INFO] add " << jcb.job_name << " to wait queue." << std::endl; , E9 ~4 b, l s. B" u" k. w4 p O* C this->wait_queue_->push(jcb);' ^# i9 w" p3 {9 q$ ~# Z) a
}% {! a& t! \" g: ]; t3 w
* v2 m- b( V8 w& f
if (!this->wait_queue_->empty()) + H0 e: u$ y! z5 [ {& r+ D6 n" Z3 q; D/ g; W
JCB jcb = this->wait_queue_->top();4 }! E+ p( [7 f. w( l
this->wait_queue_->pop(); 8 h3 y% P2 v6 W! O' W6 D 2 z! p. e: G, C, b3 b) { std::cout << "[INFO] begin to do " << jcb.job_name << "." << std::endl; 3 {8 @7 {6 y4 p jcb.job_status = Run;, P. z z0 r6 I7 A% B
// simulation do job8 B: X) u4 s; n- y4 E- L# s! Z$ T, a
sleep(1);2 k! m. B5 m6 C' `
std::cout << "[INFO] do " << jcb.job_name << " finish." << std::endl; . D8 V; s* M" N, p; o- @7 r: t( y& d! f2 N3 u. m$ s f& x# m2 \
jcb.job_status = Finish; 2 A+ X# K' D" E3 s4 s+ r // print job Data./ `) k' L! R' ^# I, F
Util::printJobData(jcb);6 ]6 V7 p8 E5 B% a8 o
this->finish_queue_->push(jcb); 0 L* h; r8 C& x1 [( C7 a7 M cur_time += jcb.required_running_time; v2 K9 o7 b% p4 R* q' n
} 1 h4 v: f( Q' T$ B else# \8 @. h- P; T/ F u
{6 d! w8 |+ ?5 j7 Q* u. D
// Slowly increase time slice when there is no job 0 k5 r3 u5 {9 B) U; H cur_time += 1; 4 ^; E0 e% c4 b& ?0 X } " Q1 {8 U2 _- m }3 i P# b4 F0 r" H
std::cout << "[INFO] all jobs finished." << std::endl; & y& V* Z+ j5 Q0 V& r! }+ w std::cout << "[LOG] average turnaround time " << (average_turnaround_time / this->job_num_) & ^2 H. l' b7 r6 `/ m1 J << " average power turnaround time " << (average_power_turnaround_time / this->job_num_) << std::endl;* |4 N" H' E7 X$ _" R" J: f9 x+ ~, ^
}5 h7 r8 }# K0 f1 b4 L
3 |$ p" Q" S1 V- R! u2 D) `9 Y
private: " I+ `' P1 b# W 1 z5 i0 Q& \2 ]/ F6 Y3 B) @' l1 C}; 6 |' v- x8 J, x. A* c: T h: W, S' ^* [& I! j% _+ E8 ]
3 R* A* f% X& m: ?# h5 v
class MultiprogrammedBatchProcessingSystemJobScheduling3 t' V0 N) O9 c2 m, E
{. x6 d# N; B4 z' O& r& P) L
public:1 A m9 }% D. O7 d9 M. Y; } X
struct PriorityCmpForPCB 5 c% {4 V8 n. o7 Q {$ P/ I. _4 X7 |' s- F4 m* P
bool operator()(const PCBptr p1, const PCBptr p2)1 B8 r$ k- W, A5 S9 P
{" j# g/ T0 Y8 ?" w; T
return p1->priority < p2->priority; , k s6 m% F% O. G }+ W. v# G' f3 |# L
};& L$ Q/ b2 _6 y
' U8 B1 r9 a+ U struct PriorityCmpForBack 4 b- ?! ?5 N4 p/ X) V: n( O2 F {: I6 x( R7 z# T* v7 Z3 [
bool operator()(const JCBptr j1, const JCBptr j2)) {8 J6 j8 X! [4 s+ y3 M" r
{ + }6 A* ]( @$ }' x return j1->submit_time > j2->submit_time;, l, T) ]* S+ w1 I2 D; x
}: f1 t- y% ^8 A6 `6 ?; @* @8 z* y
}; / s/ f3 x7 |% @: G: V j. E9 E3 d: e
* C3 b# `6 c! E5 a8 p MultiprogrammedBatchProcessingSystemJobScheduling() 7 s5 S9 s" z$ Q9 W {8 b$ [& R* C, h
back_queue_ = new std::priority_queue<JCBptr, std::vector<JCBptr>, PriorityCmpForBack>();3 O8 z7 i! a# @6 P
psa_ready_queue_ = new std::priority_queue<PCBptr, std::vector<PCBptr>, PriorityCmpForPCB>(); 9 Q3 r4 t" ~$ p) f: v, Q7 r! |5 s7 x6 N# @- ?/ k9 u, L
/ }" T( h, `) v \ std::cout << "input job num:" << std::endl; h( y8 T9 M; s9 e# P V' c
std::cin >> job_num_;0 y* \/ ?- u; {$ s
for (int i = 0; i < job_num_; i++)( ]3 n) f* x" Z% ?
{ # ?/ P" w2 b+ g2 z# Q. |. h: S9 P; | std::cout << "input job" << i << " submit_time & required_running_time & priority" << std::endl; 6 F+ n+ ]8 F7 [) Z- J I* y# |6 f0 Z9 q3 n; s6 o; O. o
JCBptr jcb = new JCB(); ) e* X4 X& j8 d: g3 s( L jcb->job_name = "job" + std::to_string(i);. b9 k. B5 l5 p
jcb->job_status = Wait; & k3 K4 w' c1 I# f std::cin >> jcb->submit_time;4 P3 ]( T/ w# a6 \1 m: [' t4 a- D! O+ a
std::cin >> jcb->required_running_time;4 n* m/ b3 n3 m( f
std::cin >> jcb->pcb->priority; y( N" U8 Y# a back_queue_->push(jcb); ' q- j+ H. }7 z5 u7 L) H9 j/ W: H }7 e' h, D+ g. g* D- ]1 q0 I
2 y# t9 J# Y7 @' D- W
/*3 S6 V2 b6 a8 {# y/ t( _0 A! v
job_num_ = 6; + S i1 p$ W+ P0 e0 L4 V * N( V& v I4 ] t0 b5 n JCBptr jcb = new JCB(); % L0 c) F; Q; Y jcb->job_name = "A"; 9 [! m. O' D& J( P& Y jcb->job_status = Wait;3 H8 Q2 N Y# ^" N
jcb->submit_time = 0; 0 T2 I/ t, K* _2 ^4 L jcb->required_running_time = 50; # g1 Z# D/ h1 B+ Q: V jcb->pcb->priority = 5; 1 o( \& u8 e/ K7 _# g$ k4 r' j# R back_queue_->push(jcb); ! ?/ d5 @3 x( B1 O + b" A, Z3 V$ a h( v2 U jcb = new JCB();9 t& Q! t+ R i4 E, z5 P& r
jcb->job_name = "B"; 9 R. t. e+ } x" \ jcb->job_status = Wait; ! b' W7 t$ I8 v* Q jcb->submit_time = 20;) p( d& `: d! e* B e( e
jcb->required_running_time = 60; % |2 J6 S ]. J" Z jcb->pcb->priority = 7; 2 t' `% G5 ^. U8 O back_queue_->push(jcb);3 C' v0 w2 ?9 j4 w7 y& p7 U
" A, l, E4 y3 I
jcb = new JCB();* V0 q. b! c; ^' B" l- ?8 ]
jcb->job_name = "C";& F& i A# x! i" h1 z! M
jcb->job_status = Wait; $ x5 d" p1 O; Q$ Z jcb->submit_time = 50;0 T) ?1 w% ~+ r8 @
jcb->required_running_time = 40; 6 F* {' ]" x7 r jcb->pcb->priority = 3; 3 \' R* Q' _9 W6 q4 Y" s( m0 f back_queue_->push(jcb); ( B* U0 Z2 R8 z8 y4 J3 U/ y! H+ s9 E. v' \1 N7 O! Y9 i
jcb = new JCB(); & W& b- U' m p J4 p; K4 S jcb->job_name = "D"; : Z8 n$ B) ~& `. ? jcb->job_status = Wait; $ u2 X3 J4 K4 u0 z& b7 M jcb->submit_time = 80; 8 I4 B- c6 C) {& ?! S! ` jcb->required_running_time = 80; 1 V- [' T2 F( y" | H0 E jcb->pcb->priority = 8;1 H/ z# } `, Y P
back_queue_->push(jcb);) O: T5 m# E* b) V# j1 ?* [
! @# R* S! u. [2 c0 K/ [
jcb = new JCB();' k! }+ ^" `/ y K0 `+ z; A. W
jcb->job_name = "E"; 7 B7 M& S; i7 l5 p/ S( h e3 R; s" c jcb->job_status = Wait; ( x" H- T& B9 p, K9 p7 b! J* n1 A& l& G. V jcb->submit_time = 100;" ?7 V% D9 i% _( z, w9 u" ]$ Z
jcb->required_running_time = 30; . r" k: w" B- h6 M jcb->pcb->priority = 6;9 I* ]& p! D' {' i
back_queue_->push(jcb);% J" ]. |/ ?0 G, b/ r/ }
W' m8 Y& a! M0 j+ q jcb = new JCB();; e9 Z0 P3 f7 _, [
jcb->job_name = "F";' \* B9 F6 T% v |% ~5 ]. w
jcb->job_status = Wait;. M4 s2 o" ~/ I. M( t
jcb->submit_time = 120;( N+ Z/ J# l+ h7 V5 x, {, {1 @
jcb->required_running_time = 70;: M/ S: x2 _1 @- U) Q: B& G- _
jcb->pcb->priority = 9; 4 t4 S5 A7 R3 @, a+ ~2 L4 G3 ?7 m* \5 l back_queue_->push(jcb);( w2 p: T t6 L3 G
*/ ' m- d# [; t. s s0 w" g; y }5 h& }7 f" p2 L$ Q
0 T) Y3 ^1 p* C1 R8 B- |2 p) G
bool start()) n# U- a. J! v6 g% S
{1 R. D1 ^6 R2 p g
cur_time = back_queue_->top()->submit_time; 7 ^' l; ^8 @7 a6 B8 H/ b5 U while (!back_queue_->empty() || !psa_ready_queue_->empty())$ Y5 C& z4 y6 N* g
{0 {/ V2 r& z) b9 R, i5 o0 |& k/ t
bool increase_time = true; + D. t+ K7 c5 P" A$ L) a // Job FCFS % Y0 P, z: O' G if(!back_queue_->empty() && psa_ready_queue_->size() < 2)1 o- G A5 o4 D- f7 l4 M. Q
{ 3 K) h% y: `7 T: t5 \) X8 M JCBptr jcb = back_queue_->top();- y2 s# k- w0 k. s
if (jcb->submit_time <= cur_time)$ t0 x# |4 F" ?: h) c6 A
{% p0 m* K; N; p. M+ x7 ?) u( L2 s9 b
back_queue_->pop(); ! k. A! s1 x. Q0 k k5 L ( d( d: j8 t3 q6 A // Process PSA 7 L% J" e* G9 N( j+ o9 Y if (!psa_ready_queue_->empty()) , \( u' J1 z) b6 I4 n { 0 r- u. y/ C5 w PCBptr pcb = psa_ready_queue_->top();4 T3 U( a4 r' W8 u, X7 b4 N& M
JCBptr jcb = pcb->jcb; ( k4 w$ `* R# F3 {7 o# y1 m2 T) X/ T7 k. S/ O7 `
if (jcb->already_run_time >= jcb->required_running_time)7 }' |1 t7 r5 a( I6 P
{ 7 D8 C0 I, V5 |2 } jcb->job_status = Finish;% z' e3 i# R: r. B4 b
psa_ready_queue_->pop(); . S# [# M/ k" u4 ^; ^6 m //std::cout << "[LOG]" << jcb->job_name << " Finish At " << cur_time << std::endl; 3 g- r0 M/ w1 E% K- I+ m& `5 `7 A$ A6 {
jcb->finish_time = cur_time;! f! {" G; Y( T7 }3 R+ ], a
Util::printJobData(*jcb, true); 4 i0 S/ C0 |0 `$ ^ }4 U! C3 `3 m9 w& B2 n' o5 e
else ; s) J9 G# r4 m! w {2 P8 ~) t9 X9 N d# O7 D @
jcb->job_status = Wait;$ C" C W( c4 T' i0 o6 K. k' X
pcb->status = Ready;7 }5 d Z- d% s+ f; q( W
//std::cout << "[LOG]" << jcb->job_name << " Ready At " << cur_time << std::endl; 5 E6 ~/ ^# ~" P9 v5 Q7 P" [ } $ B+ r$ p6 V2 M }- i6 y& J4 O! @6 T
$ o' s4 Q. h& X4 l# e: r! Y
psa_ready_queue_->push(jcb->pcb); / P+ k# R+ T5 ]1 d* m( W5 A3 K, k/ Z7 l+ u& G! A- I# X. C) u* v
PCBptr pcb = psa_ready_queue_->top();: @4 v U9 F: p
JCBptr jcb = pcb->jcb; " f) M1 @2 i7 U( \# S jcb->job_status = Run; # \1 p2 i2 _! J9 f# |) k pcb->status = Running;$ S: L/ w1 y0 v1 m) M7 }. J
1 S$ ^% l: O! }4 ~0 }, X) k
//jcb->start_time = (jcb->start_time == -1) ? cur_time : jcb->start_time; 0 w4 t7 E' Q- h //std::cout << "[LOG]" << jcb->job_name << " Begin Running At " << cur_time << std::endl;. e9 x( J* u5 s
, R2 V7 @5 u, Q& d5 p5 Z increase_time = false; / I' c8 T5 |9 g) |: a } ' {9 x' z2 A- G3 h) i } " @- _. |2 `6 F. H1 `5 r+ c else if (!psa_ready_queue_->empty()) - f4 j; d X( ?) C+ } { % G/ e) `$ E" f( G# @ {- h PCBptr pcb = psa_ready_queue_->top(); ; E+ w. ^% n# b: t3 f4 x: S! } JCBptr jcb = pcb->jcb;: z, c9 i# Q8 _& f% l# `9 }
/ _- V% k' g& P( y: D if (jcb->already_run_time >= jcb->required_running_time) 2 h: k( f# ?1 K, _: \) j9 U { 0 r( k& C; K8 N# Z: \) g& A jcb->job_status = Finish; ; s' D8 g4 o+ y* e psa_ready_queue_->pop(); 0 y: k& y0 N% O) n //std::cout << "[LOG]" << jcb->job_name << " Finish At " << cur_time << std::endl; $ T2 I7 L% v3 V$ i5 { jcb->finish_time = cur_time;* L* t" j |8 ^5 n, g* n& F7 W
increase_time = false; ' }' k" O+ X( l& Q, f7 d& I/ h' j9 S( O: M6 ^2 ?0 x8 i7 P/ G5 k
JCBptr jtop = psa_ready_queue_->top()->jcb; 0 M. R/ R9 @3 h7 x; B9 S0 P //jtop->start_time = (jtop->start_time == -1) ? cur_time : jtop->start_time;, l$ K+ `: m( k; H4 i
Util::printJobData(*jcb, true); % [. {% \1 e5 d, g4 S2 p } / r$ k' ^( {. O0 U$ K9 u- y }1 R* L% j9 q" R- i2 W7 A. i: f3 M2 D
/ T) R, B- `# h
if (increase_time) ! o0 i" E2 x( Q/ \* M/ }' i( u$ Z2 B j { ; {* H2 Q8 y! V/ G3 Y% C1 U if (!psa_ready_queue_->empty()) 2 k7 c" G/ X, c& F. p) w { 0 Z1 z6 w( Y0 C4 r3 j) { PCBptr pcb = psa_ready_queue_->top(); 7 |" d" r3 z5 u0 v pcb->jcb->already_run_time++;* l: r# J+ D: V
}+ N' e9 Z. @- Y* ]% I0 W
cur_time++;$ V4 f& b6 l; y1 O8 k
}( O5 `6 _0 R& C" s+ ^7 T1 e7 ?
} & p% f# f' ]8 G1 L std::cout << "[INFO] all jobs finished." << std::endl;$ e( r9 [, W2 a0 r' I, d2 a
std::cout << "[LOG] average turnaround time " << (average_turnaround_time / job_num_)3 l6 P6 {7 j/ A
<< " average power turnaround time " << (average_power_turnaround_time / job_num_) << std::endl; ! s- {0 l1 ]( u. C+ ` } 1 n7 i9 g. `' U1 a % @" w2 C+ G2 |3 m& Lprivate:1 [0 i% A1 M2 ?1 N# \" q `- W. e
int job_num_;5 p8 ]# d- O: ~. ]* e
std::priority_queue<JCBptr, std::vector<JCBptr>, PriorityCmpForBack>* back_queue_;- {4 \% e% V/ q8 W9 D& E9 O, f0 q. L4 W
std::priority_queue<PCBptr, std::vector<PCBptr>, PriorityCmpForPCB>* psa_ready_queue_; 1 |% k7 t! n) b% l9 u. Y8 i4 x}; # L/ T9 C6 e5 N6 T4 g7 J- U$ Y% f6 K; o: j6 U
/*+ y5 ^* h# ~( Z* H
int main()' U% M. i. l4 C$ y; P4 K* m
{/ N4 S8 U: B# b M+ t U
SimpleBatchProcessingSystemJobScheduling<FCFSSchedulingAlgorithm> js(4); / Q* V! }- c3 Q7 U0 i: f js.getCurrentReadyQueue(); 1 L/ s6 B9 e4 N4 K3 u% d3 K/ h. g5 p! G
// pause to see result : I1 U& S* \2 c getchar(); P, {8 W1 E+ _, m- \$ M% N
return 0; 9 F# v( l4 k, U) l# m7 H- U} - s$ m/ \3 x! c2 t9 _2 {' `; [*/, O j* M# z8 u- w& [
1 B5 o/ L) a6 `- A+ q
六、运行结果: [7 i' K- T) O$ {
6.1 单道批处理(FCFS)% I& P; h0 E( i0 e- k
$ x* c- F( K( @2 b7 A' G 7 F2 ~5 N& P- D1 k: b1 p9 l6.2 单道批处理(SJF) 3 H! V+ g# c# t7 P 5 j# l( X5 h8 o' e% F" Q- ]6 J p8 E. v5 i$ t/ k
6.3 单道批处理(HRRN) . n' c/ z9 s! ?" ~( W6 M7 b: c. @1 x/ ?! b
; l1 ~* P/ o$ \: z* A4 B1 W
6.4 多道批处理(FCFS + PSA) " N: \* H( F, _! p( o/ I0 ^ F3 |: F# ]5 T% `: p1 C: o
: z% h k: a) L3 }七、结尾 # A3 Q2 i/ O9 p1 o- ` 如果本文描述的内容或使用的代码存在任何问题,请及时联系我或在本篇文章的下面进行评论,我会本着对每一位学技术同学的负责态度立即修改。在后续还会有三篇计算机操作系统的算法 C++ 复现博文,如果感兴趣可以关注我。 ; x2 X1 z8 d& n————————————————9 d3 I% v/ B$ F0 W; x, R2 r/ ]
版权声明:本文为CSDN博主「杨小帆_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。4 j9 h5 [9 Y$ C+ o) W
原文链接:https://blog.csdn.net/qq_40697071/article/details/106698130 ! M O, i+ j! R: e9 P8 I. W' L7 m1 y