设计一个内存工作区,并使用下述算法来模拟实现页面的置换:
1、最佳页面置换算法(OPT)
2、先进先出页面置换算法(FIFO)
3、最近最久未使用页面置换算法(LRU)
模拟出对于一个进程的各个页面访问过程中,内存工作区的存储情况(包括页面的调入和调出情况),并记录缺页情况,最后计算显示缺页率。
1、通过随机数(也可以是固定的页面引用序列)产生一个指定范围内的页面号引用串(页号的最大值可以是动态的,如7;页面号引用串的数目也可以是动态,如20),如
7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1。
2、给定为进程分配的物理块数,如3块。
3、在进程运行过程中,若其要访问的页面不在内存中,则需要把它调入内存,当内存没有空间时,为保证进程能正常工作,系统必须从内存中调出一页程序或数据送到磁盘的对换区中。
4、采用最佳页面置换算法(OPT)模拟出对于一个进程的各个页面访问过程中,内存工作区的存储情况(包括页面的调入和调出情况),并记录缺页情况,最后计算显示缺页率。
5、采用先进先出页面置换算法(FIFO)模拟出对于一个进程的各个页面访问过程中,内存工作区的存储情况(包括页面的调入和调出情况),并记录缺页情况,最后计算显示缺页率。
6、采用最近最久未使用页面置换算法(LRU)模拟出对于一个进程的各个页面访问过程中,内存工作区的存储情况(包括页面的调入和调出情况),并记录缺页情况,最后计算显示缺页率。
老规矩,先初始化一些全局变量,包括固定页面引用序列(注:此处也可以随机产生序列),三个物理块对应的数组,统计缺页次数的变量初始次数为3(初始的三个物理块为空),线程,用户输入的时间片长度等。
public static int[] arr = {
7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1 };
public static int[] arr1 = new int[3];//物理块内存
public static int h = 3;//缺页次数
Thread t1;
int time;//时间片长度
初始化arr1数组,将序列的前三个页面转载进内存块,调用load函数修改指定物理块的颜色并维持用户指定时间片长度的时间并将对应的装载信息写入到textbox中。
public void updatearr1() {
for (int i = 0; i < 3; i++) {
arr1[i] = arr[i];
this.tbdanqian.Text = arr[i].ToString();
load(i);
}
}
然后编写一些函数以简化页面置换算法的代码。
load函数:将前三个页面装载入内存,修改对应的内存块的颜色维持一定的时间后再恢复原来的颜色并把页面装载信息加载到textbox中。
public void load(int i) {
if (i == 0)
{
Thread.Sleep(time);
this.tb0.Text = arr1[i].ToString();
this.tb0.BackColor = Color.Yellow;
Thread.Sleep(time);
this.tb0.BackColor = Color.White;
this.tbnews.AppendText("页块" + i + " # 被装载\r\n");
}
else if (i == 1)
{
Thread.Sleep(time);
this.tb1.Text = arr1[i].ToString();
this.tb1.BackColor = Color.Yellow;
Thread.Sleep(time);
this.tb1.BackColor = Color.White;
this.tbnews.AppendText("页块" + i + " # 被装载\r\n");
}
else
{
Thread.Sleep(time);
this.tb2.Text = arr1[i].ToString();
this.tb2.BackColor = Color.Yellow;
Thread.Sleep(time);
this.tb2.BackColor = Color.White;
this.tbnews.AppendText("页块" + i + " # 被装载\r\n");
}
}
函数功能: 判断当前页是否缺页
public static bool isChuZai(int page) {
for (int i=0;i<3;i++) {
if (arr1[i]==arr[page]) {
//三个物理块中包括当前页
return false;//不缺页
}
}
return true;//否则缺页
}
replace()函数功能: 替换页面 ,代码实现与load函数类似。
public void replace(int index,int page) {
//参数1:物理块索引,参数2:要装入页面
if (index == 0)
{
Thread.Sleep(time);
this.tb0.Text = page.ToString();
this.tb0.BackColor = Color.Red;
Thread.Sleep(time);
this.tb0.BackColor = Color.White;
this.tbnews.AppendText("页块" + index + " # 被替换\r\n");
}
else if (index== 1)
{
Thread.Sleep(time);
this.tb1.Text = page.ToString();
this.tb1.BackColor = Color.Red;
Thread.Sleep(time);
this.tb1.BackColor = Color.White;
this.tbnews.AppendText("页块" + index + " # 被替换\r\n");
}
else
{
Thread.Sleep(time);
this.tb2.Text = page.ToString();
this.tb2.BackColor = Color.Red;
Thread.Sleep(time);
this.tb2.BackColor = Color.White;
this.tbnews.AppendText("页块" + index + " # 被替换\r\n");
}
}
命中页面,代码实现与load函数类似。
public void setshot(int page) {
Thread.Sleep(time);
if (page == arr1[0])
{
this.tb0.BackColor = Color.Yellow;
Thread.Sleep(time);
this.tb0.BackColor = Color.White;
this.tbnews.AppendText("页块" + 0 + " # 被命中\r\n");
}
else if (page == arr1[1])
{
this.tb1.BackColor = Color.Yellow;
Thread.Sleep(time);
this.tb1.BackColor = Color.White;
this.tbnews.AppendText("页块" + 1 + " # 被命中\r\n");
}
else {
this.tb2.BackColor = Color.Yellow;
Thread.Sleep(time);
this.tb2.BackColor = Color.White;
this.tbnews.AppendText("页块" + 2 + " # 被命中\r\n");
}
}
有了这些函数的加持,接下来就可以开始编写页面置换算法到代码了。
该算法的思路为:缺页时,计算内存中每个逻辑页面的下一次访问时间。
将以后永不使用的,或未来最长时间内不再被访问的页面替换掉。
这种算法可以保证最低的缺页率。
但是由于现实中无法得到之后会访问的页面序列,所以该算法只是理论上的页面置换算法。
public void OPT() {
updatearr1();
for (int i = 3; i < arr.Length; i++) {
if (isChuZai(i))
{
//缺页
int x = getindex(i);//获取需要被替换的物理块索引
arr1[x] = arr[i];
h++;
this.tbdanqian.Text = arr[i].ToString();
replace(x,arr[i]);
}
else {
this.tbdanqian.Text = arr[i].ToString();
setshot(arr[i]);
}
}
this.lbh.Text = h.ToString();
this.lbx.Text = (((float)h / 20) * 100).ToString() + "%";
}
算法中用到了一个之前没提到的getindex函数:通过从当前缺页的下一个位置开始计数找到需要被替换的页面所对应物理块的索引并返回。
public int getindex(int index)
{
int x=0, y=0, z=0;
for (int i=index+1;i<arr.Length;i++) {
if (arr[i] != arr1[0])
{
x++;
}
else {
break;
}
}
for (int i = index + 1; i < arr.Length; i++)
{
if (arr[i] != arr1[1])
{
y++;
}else
{
break;
}
}
for (int i = index + 1; i < arr.Length; i++)
{
if (arr[i] != arr1[2])
{
z++;
}else {
break;
}
}
return (x> y && x>z)?0:(y>x && y>z)?1: 2;
}
该算法的思路是:先进先出:淘汰在内存驻留时间最长的页。
实现
内存中页面按先后次序链接成一个队列,设置一-个替换指针,使它总是指向最老的页面,每次缺页时替换该指针所指向的页面。
特点
➢这种算法简单,实现容易;
➢貌似公平,实际上不公平;
➢不切实际,有些页面经常被访问,可能先被淘汰,性能差。
public void FIFO() {
updatearr1();//初始化前三个页面
int index = 0;//记录要替换的页块的替换指针
for (int i=3;i<arr.Length;i++) {
if (isChuZai(i)){
//缺页
arr1[index] = arr[i];//修改数组
this.tbdanqian.Text = arr[i].ToString();
h++;//统计缺页次数
replace(index,arr[i]);//替换页面
index++;//索引加1
if (index == 3) index = 0;
}
else
{
this.tbdanqian.Text = arr[i].ToString();
setshot(arr[i]);
}
}
this.lbh.Text = h.ToString();
this.lbx.Text = (((float)h / 20) * 100).ToString() + "%";
}
思路
选择在最近一段时间最久未使用的页面予以淘汰。
实现
缺页时,计算内存中的每个逻辑页面的上一次访问时间。选择上一次使用到当前时间最长的页面,即最后一次被使用到发生调度的时间长短。
该算法与最优页面置换算法相类似,不同的是该算法是从当前缺页位置往前查找最近最久为使用的页面进行替换。
public void LRU() {
updatearr1();//初始化前三个页面
for (int i = 3; i < arr.Length; i++)
{
if (isChuZai(i))
{
//缺页
int index = getindex1(i);
arr1[index] = arr[i];//修改数组
this.tbdanqian.Text = arr[i].ToString();
h++;//统计缺页次数
replace(index, arr[i]);//替换页面
}
else
{
this.tbdanqian.Text = arr[i].ToString();
setshot(arr[i]);
}
}
this.lbh.Text = h.ToString();
this.lbx.Text = (((float)h / 20) * 100).ToString() + "%";
}
上述算法中用到的getindex1()函数:用来向前查找最近最久未使用的页面并返回器对应的物理块索引。
public int getindex1(int index) {
int x = 0, y = 0, z = 0;
for (int i = index -1; i>=0; i--)
{
if (arr[i] != arr1[0])
{
x++;
}
else
{
break;
}
}
for (int i = index - 1; i >=0; i--)
{
if (arr[i] != arr1[1])
{
y++;
}
else
{
break;
}
}
for (int i = index - 1; i >=0; i--)
{
if (arr[i] != arr1[2])
{
z++;
}
else
{
break;
}
}
return (x > y && x > z) ? 0 : (y > x && y > z) ? 1 : 2;
}
最后是窗体中一些按钮的点击事件。
//产生序列按钮点击事件
private void button1_Click(object sender, EventArgs e)
{
for (int i=0;i<arr.Length;i++) {
//将数组的序列添加到textbox中
this.tbxulie.AppendText(arr[i]+",");
}
}
//开始模拟按钮点击事件
private void button2_Click(object sender, EventArgs e)
{
time = int.Parse(this.tbtime.Text);//获取用户输入的时间片的值
if (rb1.Checked)//根据用户的选项执行对应的算法
{
t1 = new Thread(new ThreadStart(OPT));
t1.Start();
}
else if (rb2.Checked)
{
t1 = new Thread(new ThreadStart(FIFO));
t1.Start();
}
else if (rb3.Checked)
{
t1 = new Thread(new ThreadStart(LRU));
t1.Start();
}
else {
MessageBox.Show("请选择要模拟的算法!!!" , "提示");
}
}
//清除屏幕按钮点击事件
private void button3_Click(object sender, EventArgs e)
{
this.tbnews.Text = "";
this.tbdanqian.Text = "";
this.tb0.Text = "";
this.tb1.Text = "";
this.tb2.Text = "";
h = 3;
this.lbh.Text = "";
this.lbx.Text = "";
}
private void button4_Click(object sender, EventArgs e)
{
System.Environment.Exit(0);
}
点击产生序列,要模拟的序列被加载到textbox中,选择最佳页面置换算法点击开始模拟,系统系统开始模拟页面置换过程,将对应的信息打印到右边的textbox中,最后计算出缺页次数和缺页率显示在屏幕上。效果如图所示。
点击清空屏幕清空内容,选择先进先出算法后点击开始模拟,系统动态演示页面置换过程,效果如图所示。
点击清空屏幕清空内容,选择最近最久未使用算法后点击开始模拟,系统动态演示页面置换过程,效果如图所示。