一、实验目的
- 对页面置换做进一步的理解。
- 了解页面置换的任务。
- 通过编程掌握页面置换算法及缺页率计算。
- 了解Belady现象和抖动现象。
二、实验内容
- 输入给出一组页面访问顺序(如页面走向是1、2、5、7、5、7、1、4、3、5、6、4、3、2、1、5、2)。
- 分配给该作业一定的物理块(如3块、4块等)(要求是输入)。
- 分别利用OPT、FIFO、LRU页面置换算法模拟页面置换过程并输出换进和换出的页面号。
- 计算每种面置换算法缺页率并输出。
- 通过多次运行获得的结果进行比对,并对比对结果进行说明。
三、代码
一、 源代码(含注释)
1. #include <iostream>
2. using namespace std;
3. #define countyh 12 //总页号数
4.
5. class YMZH
6. {
7. public:
8. int ymh[countyh] ={ 1,2,3,4,1,2,5,1,2,3,4,5 }; //页面访问顺序
9. //int wlk[3] = {-1,-1,-1}; //3个物理块
10. int wlk_count;//物理块数(用户输入)
11. int *wlkptr = new int[wlk_count];
12. int wlkcount = wlk_count;//物理块数
13. int wlkcount1 = wlkcount;
14. void OPT();
15. void FIFO();
16. void LRU();
17. };
18. void YMZH::OPT() {
19. int count_hcyh = 0;//统计被换出的页号,即缺页次数,输出一次加一次
20. cout << "-------------------------------------------------------------------------------" << endl;
21. cout << "\t\t\t最佳页面置换算法OPT" << endl << endl;
22. cout << "请输入物理块的数量:";
23. cin >> wlk_count;//用户输入的物理数量
24. cout << "序号\t" << "换入页号\t";
25. for (int i = 0; i < wlk_count; i++)
26. {
27. *(wlkptr + i) = -1;//物理块号初始化为-1,表示没有页号进入
28. cout << "块" << i + 1 <<"\t";
29. }
30. cout<<"是否缺页 " << "换出页号" << endl;
31. cout << "-------------------------------------------------------------------------------" << endl;
32. /*
33. 1、第一行
34. */
35. cout << " " << 0 << "\t ";//序号
36. cout << endl;
37. cout << "-------------------------------------------------------------------------------" << endl;
38.
39. /*
40. 2、处理空闲物理块代码
41. n个物理块数量行,因为初始状态物理块是空闲的,可以直接转入页号
42. */
43. for (int i = 0; i <wlk_count; i++)
44. {
45. cout<<" "<<i+1<< "\t ";//序号
46. cout << ymh[i] << "\t ";//换入页号 程序执行页面号顺序
47.
48. *(wlkptr + i) = ymh[i];
49. for (int k = 0; k < wlk_count; k++) // *******循环输出每一个块
50. {
51. cout << *(wlkptr + k) << "\t ";//块 输出物理块号内的页面号
52. }
53. cout <<" " << "是" << "\t\t" << endl; //是否缺页
54. cout << "-------------------------------------------------------------------------------" << endl;
55. }
56.
57. /*
58. 3、开始根据最长时间未使用原则置换页面
59. */
60.
61. for (int i = wlk_count; i < countyh; i++)
62. {
63. cout << " " << i+1 << "\t ";//序号
64. cout << ymh[i] << "\t ";//换入页号 程序执行页面号顺序
65.
66.
67. //--------------如果下一个访问的页号(从ymh[wlk_count]开始)还在物理块中就不置换,直接输出内容,无缺页发生
68. int sign = 0;//标记位,如果下一个页号在某个物理块中sign就等于1
69. for (int j = 0; j < wlk_count; j++)
70. {
71. if (ymh[i] == *(wlkptr + j)) sign = 1;
72. }
73.
74.
75. //----------------A、说明下一个页号已经在物理块中,无须置换,直接输出
76. if (sign == 1)
77. {
78. for (int k = 0; k < wlk_count; k++) // *******循环输出每一个块
79. {
80. cout << *(wlkptr + k) << "\t ";//块 输出物理块号内的页面号
81. }
82. cout << " " << "否" << "\t\t" << endl; //是否缺页
83. cout << "-------------------------------------------------------------------------------" << endl;
84. }
85. //----------------B、如果下一个页号不再物理块中 每种算法的核心代码、核心思想在此,其他地方都一样的实现-------------------------------
86. else {
87. //为每一个物理块设计一个时间条,看谁最长时间,就置换谁
88. int* time = new int[wlk_count] ();//小括号代表所有值都初始化为0
89. int all_time = 1;// 计数总时间、比较一次加一
90.
91. for (int j = i + 1; j < countyh; j++) {
92. for (int m = 0; m < wlk_count; m++)
93. {
94. if (*(wlkptr + m) == ymh[j] && (*(time + m))==0) //从当前要进入物理块的页号的下一个页号开始查找谁时间最长
95. {
96. (*(time+m))= all_time;//如果某个物理块的页号等于页号顺序中的,则保持第一次出现的时间
97. }
98. all_time++;//比较完一个页号就时间加1
99. }
100. }
101. //以上循环遍历后,就得出了每一个物理块中页号在未来序列中第一次出现的时间,看谁最长,就置换谁
102. if (*(time + 0) == 0) {
103. *(time + 0) = 20;
104. }
105. int max_time = *(time + 0);//假设第一个物理块号里面的页号时间最大
106. int max_yh=1;//记录最大时间的序号,即物理块号
107. for (int i = 1; i < wlk_count; i++)
108. {
109. if (*(time + i) == 0)
110. {
111. *(time + i) = 20 - i;//如果物理块中的页号在未来不再出现,时间就会是0,所以这里直接赋大值来置换该页号
112. }
113. if (*(time + i) > max_time) {
114. max_time = *(time + i);
115. max_yh = i + 1;//记录物理块号,也就是要被置换的
116. }
117. }
118. int hcyh= *(wlkptr + max_yh - 1);//先记录被换出的页面号
119. *(wlkptr + max_yh - 1) = ymh[i];//开始置换,输出
120. for (int k = 0; k < wlk_count; k++) // *******循环输出每一个块
121. {
122. cout << *(wlkptr + k) << "\t ";//块 输出物理块号内的页面号
123. }
124. cout << " " << "是"; //是否缺页
125. cout << "\t\t" << hcyh << "\t\t" << endl; //换出页号
126. count_hcyh++;
127. cout << "-------------------------------------------------------------------------------" << endl;
128. }
129. }//大for循环结束
130. /*
131. 计算缺页次数、缺页率
132. 缺页次数=物理块数+过程中置换的次数
133. 缺页率=缺页次数/总页号数量
134. */
135. cout << endl << "缺页次数:" << wlk_count + count_hcyh << endl;
136. float qyl = (wlk_count + count_hcyh + 0.0) / countyh;
137. cout << "缺页率:" << qyl << endl << endl;
138.
139. /* 思考:
140. 上面if里面都是当物理块最初为空时,可以直接把页号放入的。
141. 此时物理块已经满,只能调换页面号。
142. 采用最佳页面置换算法—把此时物理块里面的页面在未来最后被使用的一个页面号用来置换
143. 如何解决物理块中的页面号在未来谁最后才被使用或一直未使用。
144. 从当前序号的页面顺序中开始遍历未使用的页号,与物理块中的页号比较
145. 相同:则计算该页号下一次使用时距离此时的间隔是多少,一共计算三个物理块中的所有页号。
146. 保存后面的页号的第一次出现的时间,比较大小,谁大就置换谁
147. */
148.
149.
150. /*
151. 如果循环比较完后发现时间还是为0说明后面的顺序已经没有还页号,直接使用该页号置换
152. 特别是最后页号越来越少,会出现多个页号都不在页号顺序里面了,我们设计默认第一个物理块置换,所以时间最大
153. */
154. }
155.
156. void YMZH::FIFO() {
157. int count_hcyh = 0;//统计被换出的页号,即缺页次数,输出一次加一次
158. cout << "-------------------------------------------------------------------------------" << endl;
159. cout << "\t\t\t先进先出页面置换算法FIFO" << endl << endl;
160. cout << "请输入物理块的数量:";
161. cin >> wlk_count;//用户输入的物理数量
162. cout << "序号\t" << "换入页号\t";
163. int *pri = new int[wlk_count];
164. for (int i = 0; i < wlk_count; i++)
165. {
166. *(wlkptr + i) = -1;//物理块号初始化为-1,表示没有页号进入
167. *(pri + i) = i+1;//优先级数设计等于块标号
168. cout << "块" << i + 1 << "\t";
169. }
170. cout << "是否缺页 " << "换出页号" << endl;
171. cout << "-------------------------------------------------------------------------------" << endl;
172. /*
173. 1、第一行
174. */
175. cout << " " << 0 << "\t ";//序号
176. cout << endl;
177. cout << "-------------------------------------------------------------------------------" << endl;
178.
179. /*
180. 2、处理空闲物理块代码
181. n个物理块数量行,因为初始状态物理块是空闲的,可以直接转入页号
182. */
183. for (int i = 0; i < wlk_count; i++)
184. {
185. cout << " " << i + 1 << "\t ";//序号
186. cout << ymh[i] << "\t ";//换入页号 程序执行页面号顺序
187.
188. *(wlkptr + i) = ymh[i];
189. for (int k = 0; k < wlk_count; k++) // *******循环输出每一个块
190. {
191. cout << *(wlkptr + k) << "\t ";//块 输出物理块号内的页面号
192. }
193. cout << " " << "是" << "\t\t" << endl; //是否缺页
194. cout << "-------------------------------------------------------------------------------" << endl;
195. }
196. for (int i = wlk_count; i < countyh; i++)
197. {
198. cout << " " << i + 1 << "\t ";//序号
199. cout << ymh[i] << "\t ";//换入页号 程序执行页面号顺序
200.
201.
202. //--------------如果下一个访问的页号(从ymh[wlk_count]开始)还在物理块中就不置换,直接输出内容,无缺页发生
203. int sign = 0;//标记位,如果下一个页号在某个物理块中sign就等于1
204. for (int j = 0; j < wlk_count; j++)
205. {
206. if (ymh[i] == *(wlkptr + j)) sign = 1;
207. }
208.
209.
210. //----------------A、说明下一个页号已经在物理块中,无须置换,直接输出
211. if (sign == 1)
212. {
213. for (int k = 0; k < wlk_count; k++) // *******循环输出每一个块
214. {
215. cout << *(wlkptr + k) << "\t ";//块 输出物理块号内的页面号
216. }
217. cout << " " << "否" << "\t\t" << endl; //是否缺页
218. cout << "-------------------------------------------------------------------------------" << endl;
219. }
220.
221. //执行判断谁最先进入物理块中,谁就被置换
222. //给每一个物理块设计一个优先级*pri,块1开始优先级最大,依次类推逐渐减小
223.
224. else
225. {
226. //比较谁的pri更小
227. int min_pri = *(pri + 0);//首先假设第一个物理块的优先级最大,即最先进入
228. int first=1;
229. //第一个物理块后面的所有物理块依次和第一个物理块比较优先级,
230. //发现更小的数即优先级更大的就赋值min_pri,并记录下该物理块的标号
231. for (int m = 1; m < wlk_count; m++)
232. {
233. if (min_pri > (*(pri + m))) {
234. min_pri = *(pri + m);
235. first = m+1;//记录最先进入的页号在哪一个物理块中,是块的标号,在数组中要减1才代表该块
236. }
237. }
238.
239. int hcyh = *(wlkptr + first - 1);//先记录被换出的页面号
240. *(wlkptr + first - 1) = ymh[i];//开始置换,输出
241. //置换后此时的物理块的页号是最新加入,所有优先级最小,即数值最大为物理块的数量
242. //而其他的物理块中的优先级数依次增大,即数值减1
243. for (int i = 0; i < wlk_count; i++)
244. {
245. if (i == first - 1) {
246. *(pri + first - 1) = wlk_count;
247. }
248. else
249. {
250. (*(pri + i))--;
251. }
252. }
253.
254. for (int k = 0; k < wlk_count; k++) // *******循环输出每一个块
255. {
256. cout << *(wlkptr + k) << "\t ";//块 输出物理块号内的页面号
257. }
258. cout << " " << "是"; //是否缺页
259. cout << "\t\t" << hcyh << "\t\t" << endl; //换出页号
260. count_hcyh++;
261. cout << "-------------------------------------------------------------------------------" << endl;
262. }
263. }//for循环结束
264. cout << endl << "缺页次数:" << wlk_count + count_hcyh << endl;
265. float qyl = (wlk_count + count_hcyh + 0.0) / countyh;
266. cout << "缺页率:" << qyl << endl << endl;
267. }
268.
269. void YMZH::LRU() {
270. int count_hcyh = 0;//统计被换出的页号,即缺页次数,输出一次加一次
271. cout << "-------------------------------------------------------------------------------" << endl;
272. cout << "\t\t\t最近最久未使用页面置换算法LRU" << endl << endl;
273. cout << "请输入物理块的数量:";
274. cin >> wlk_count;//用户输入的物理数量
275. cout << "序号\t" << "换入页号\t";
276. int* pri = new int[wlk_count];
277. for (int i = 0; i < wlk_count; i++)
278. {
279. *(wlkptr + i) = -1;//物理块号初始化为-1,表示没有页号进入
280. *(pri + i) = i + 1;//优先级数设计等于块标号
281. cout << "块" << i + 1 << "\t";
282. }
283. cout << "是否缺页 " << "换出页号" << endl;
284. cout << "-------------------------------------------------------------------------------" << endl;
285. /*
286. 1、第一行
287. */
288. cout << " " << 0 << "\t ";//序号
289. cout << endl;
290. cout << "-------------------------------------------------------------------------------" << endl;
291.
292. /*
293. 2、处理空闲物理块代码
294. n个物理块数量行,因为初始状态物理块是空闲的,可以直接转入页号
295. */
296. for (int i = 0; i < wlk_count; i++)
297. {
298. cout << " " << i + 1 << "\t ";//序号
299. cout << ymh[i] << "\t ";//换入页号 程序执行页面号顺序
300.
301. *(wlkptr + i) = ymh[i];
302. for (int k = 0; k < wlk_count; k++) // *******循环输出每一个块
303. {
304. cout << *(wlkptr + k) << "\t ";//块 输出物理块号内的页面号
305. }
306. cout << " " << "是" << "\t\t" << endl; //是否缺页
307. cout << "-------------------------------------------------------------------------------" << endl;
308. }
309. for (int i = wlk_count; i < countyh; i++)
310. {
311. cout << " " << i + 1 << "\t ";//序号
312. cout << ymh[i] << "\t ";//换入页号 程序执行页面号顺序
313.
314.
315. //--------------如果下一个访问的页号(从ymh[wlk_count]开始)还在物理块中就不置换,直接输出内容,无缺页发生
316. int sign = 0;//标记位,如果下一个页号在某个物理块中sign就等于1
317. for (int j = 0; j < wlk_count; j++)
318. {
319. if (ymh[i] == *(wlkptr + j)) sign = 1;
320. }
321.
322.
323. //----------------A、说明下一个页号已经在物理块中,无须置换,直接输出
324. if (sign == 1)
325. {
326. for (int k = 0; k < wlk_count; k++) // *******循环输出每一个块
327. {
328. cout << *(wlkptr + k) << "\t ";//块 输出物理块号内的页面号
329. }
330. cout << " " << "否" << "\t\t" << endl; //是否缺页
331. cout << "-------------------------------------------------------------------------------" << endl;
332. }
333.
334. //LRU算法,最近最久未被使用的页号被置换出去
335. //思考:最近最久未使用,想来和OPT算法未来最长时间未使用刚好相反
336. //所以这里使用循环遍历已经访问过的页号顺序,每一个物理块中的页号与前面的页号一一比较,
337. //相同的则时间等于当前时间(开始就设计一个总时间从0开始,数越大表示越久被使用过)
338. //思想和OPT算法一样,只是循环遍历的方向刚好相反
339. else {
340. //为每一个物理块设计一个时间条,看谁最长时间,就置换谁
341. int* time = new int[wlk_count]();//小括号代表所有值都初始化为0
342. int all_time = 1;// 计数总时间、比较一次加一
343.
344. //从下一个要访问的页号i的上一个页号i-1开始一直遍历到第一个页号
345. for (int j = i - 1; j >= 0; j--) {
346. for (int m = 0; m < wlk_count; m++)
347. {
348. if (*(wlkptr + m) == ymh[j] && (*(time + m)) == 0) //从当前要进入物理块的页号的下一个页号开始查找谁时间最长
349. {
350. (*(time + m)) = all_time;//如果某个物理块的页号等于页号顺序中的,则保持第一次出现的时间
351. }
352. all_time++;//比较完一个页号就时间加1
353. }
354. }
355. //以上循环遍历后,就得出了每一个物理块中页号在已被访问的序列中第一次出现的时间,看谁最长,就置换谁
356. if (*(time + 0) == 0) {
357. *(time + 0) = 20;
358. }
359. int max_time = *(time + 0);//假设第一个物理块号里面的页号时间最大
360. int max_yh = 1;//记录最大时间的序号,即物理块号
361. for (int i = 1; i < wlk_count; i++)
362. {
363. if (*(time + i) == 0)
364. {
365. *(time + i) = 20 - i;//如果物理块中的页号在未来不再出现,时间就会是0,所以这里直接赋大值来置换该页号
366. }
367. if (*(time + i) > max_time) {
368. max_time = *(time + i);
369. max_yh = i + 1;//记录物理块号,也就是要被置换的
370. }
371. }
372. int hcyh = *(wlkptr + max_yh - 1);//先记录被换出的页面号
373. *(wlkptr + max_yh - 1) = ymh[i];//开始置换,输出
374. for (int k = 0; k < wlk_count; k++) // *******循环输出每一个块
375. {
376. cout << *(wlkptr + k) << "\t ";//块 输出物理块号内的页面号
377. }
378. cout << " " << "是"; //是否缺页
379. cout << "\t\t" << hcyh << "\t\t" << endl; //换出页号
380. count_hcyh++;
381. cout << "-------------------------------------------------------------------------------" << endl;
382. }
383. }//大for循环结束
384. /*
385. 计算缺页次数、缺页率
386. 缺页次数=物理块数+过程中置换的次数
387. 缺页率=缺页次数/总页号数量
388. */
389. cout << endl << "缺页次数:" << wlk_count + count_hcyh << endl;
390. float qyl = (wlk_count + count_hcyh + 0.0) / countyh;
391. cout << "缺页率:" << qyl << endl << endl;
392.
393. }
394.
395.
396. void main() {
397.
398. YMZH ymzh;
399. ymzh.OPT();
400. ymzh.OPT();
401. ymzh.FIFO();
402. ymzh.FIFO();
403. ymzh.LRU();
404. ymzh.LRU();
405. system("pause");406.
406. }
四、实验结果
1、最佳页面置换算法OPT实验结果:
2、先进先出页面置换算法FIFO实验结果:
3、 最近最久未使用页面置换算法LRU