银行家算法 C# 界面动态实现
提示:以下是本篇文章正文内容,下面案例可供参考
一、获取进程数据
-
获取数据部分,初始界面为(图1),其中max,allocation,need,avalible矩阵,均采用富文本框RichTextBox获取,其他文本框采用TextBox ,”录入数值”按钮用来填写数据后,录入数据并初始化表格界面,其中若输入数据不满足:
need[i, j] == max[i, j] – allocation[i, j]
会出现提示框
MessageBox.Show(“输入数据不符合要求。”);
输入测试数据后如图2
#region 获取数据
private void button2_Click_1(object sender, EventArgs e)
{
n = int.Parse(tb_n.Text);//进程数
m = int.Parse(tb_m.Text);//资源数 建议1~6,否则印象美观
//初始化Max
for (int i = 0; i < n; i++)
{
string lineStr = rtb_max.Lines[i];
string[] b = new string[m];
b = lineStr.Split();
int j = b.Length;
for (int k = 0; k < j; k++)
{
max[i, k] = int.Parse(b[k]);
}
}
//初始化Allocation
for (int i = 0; i < n; i++)
{
string lineStr = rtb_allo.Lines[i];
string[] b = new string[m];
b = lineStr.Split();
int j = b.Length;
for (int k = 0; k < j; k++)
{
allocation[i, k] = int.Parse(b[k]);
}
}
//初始化Need
for (int i = 0; i < n; i++)
{
string lineStr = rtb_need.Lines[i];
string[] b = new string[m];
b = lineStr.Split();
int j = b.Length;
for (int k = 0; k < j; k++)
{
need[i, k] = int.Parse(b[k]);
}
}
//初始化Avaliable
string[] s = new string[m];
string Str = rtb_aval.Lines[0];
s = Str.Split();
for (int k = 0; k < m; k++)
{
available[k] = int.Parse(s[k]);
}
//监测数据输入是否合法need[i, j] == max[i, j] - allocation[i, j]
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (need[i, j] != max[i, j] - allocation[i, j])
MessageBox.Show("输入数据不符合要求。");
}
}
Finish = new bool[n];//初始化Finish[i] =false,表示各进程都未访问过,用来表示表格中finish列的值
Work = new int[m];//初始化work[]矩阵,值为available[],因为DrawCharts()函数的work+available列的数据就是work[]的值
for (int i = 0; i < n; i++)
{
Finish[i] = false;
}
for (int i = 0; i < m; i++)
{
Work[i] = available[i];
}
DrawCharts();//初始化原始数据得到的表格
}
二、界面部分
界面部分最难受,因为我也感觉很丑,但头痛的不只是它老土的外观,遇到好多问题。这个表格大部分是用C#的winform 中的Graphic类,画出来的,每次数据更新后都要重绘。以下是遇到的问题,及解决方法。
-
为了绘制图形之后不消失,就是别的窗口遮盖后,图画没有了的现象;或者是最小化后图画消失了的情况,综合难易之后,我采用把画下来的图片保存在picturebox上,原因借鉴这个文章。他虽然也讲到了在bitmap中画,然后在pictureBox中显示的方法,但是当时并不知道这个方法可以避免闪烁。
C# 画图画不出来的解决办法
-
每次需要重绘时,如何清空pictureBox里 的图片: g.Clear(Color.White); g是Graphic对象,也是参考了别人的,当时想能不能,用背景图片清空picturebox,因为这样可能就是窗口整体图案一致,但g.Clear(
这里必须是颜色
),就没办法解决了,所以可以看到图2窗口上有白白的很不和谐的那一片区域(就是picturebox的位置) -
picturebox刷新图像的闪烁问题解决方法,参考了两个文章:那个明白看那个,都类似,大致思路都把图绘在bitmap上,绘完之后,把bitmap赋值给picturebox,就可以解决picturebox绘图闪烁问题
C# winform 高效绘图
C#.net picturebox动画效果,刷新图像的闪烁问题解决方法
-
参考别人的文章后,发现用完之后要dispose,否则内存爆炸
b.Dispose();
b = null;
g.Dispose();
g = null;
g2.Dispose();
g2 = null; - 更换背景图中,发现图片怎么也不能完全填充窗口,如下图a,记得BackgroundImage调成Stretch,更改之后就如下图b和图c和图d
6. 以下代码中注释部分,是代码过程中试错部分,看了没啥用的,直接跳过就好(所有代码的注释部分都不用看)
#region 初始化表格
void DrawCharts() {
Bitmap b = new Bitmap(1200, 600);
Graphics g = Graphics.FromImage(b);
//pB = pictureBox1;
//Graphics g = this.CreateGraphics();
//Graphics g = pictureBox1.CreateGraphics();
g.Clear(Color.White);
Rectangle r1;
//左一列
r1 = new Rectangle(0, 0, 60, 20);
g.DrawRectangle(penBlack, r1);
g.DrawString("资源情况", myfont, BrushBlack, r1, format);
r1 = new Rectangle(0, 20, 60, 20);
g.DrawRectangle(penBlack, r1);
g.DrawString("进程", myfont, BrushBlack, r1, format);
for (int i = 0; i < n; i++)
{
r1 = new Rectangle(0, i * 20 + 40, 60, 20);
g.DrawRectangle(penBlack, r1);
g.DrawString("进程 " + i, myfont, BrushBlack, r1, format);
}
//上一行
for (int i = 0; i < 4; i++)
{
r1 = new Rectangle(60 + i * (40 * m), 0, 40 * m, 20);
g.DrawRectangle(penBlack, r1);
g.DrawString(word[i], myfont, BrushBlack, r1, format);
}
r1 = new Rectangle(60 + 4 * (40 * m), 0, 40, 40);
g.DrawRectangle(penBlack, r1);
g.DrawString(word[4], myfont, BrushBlack, r1, format);
//上二行
for (int i = 0; i < 4 * m; i++)
{
r1 = new Rectangle(60 + i * 40, 20, 40, 20);
g.DrawRectangle(penBlack, r1);
g.DrawString(letters[i % m], myfont, BrushBlack, r1, format);
}
//数字区域
rectangles = new Rectangle[n * 3 * m];
for (int i = 0; i < n; i++)
for (int j = 0; j < 3 * m; j++)
{
//画矩形
rectangles[i * 3 * m + j] = new Rectangle(j * 40 + 60, 40 + i * 20, 40, 20);
r1 = rectangles[i * 3 * m + j];
g.DrawRectangle(penBlack, r1);
//字符
if (j < m)
{
g.DrawString(Convert.ToString(max[i, j]), myfont, BrushBlack, r1, format);
}
else if (j < 2 * m)
{
g.DrawString(Convert.ToString(need[i, j % m]), myfont, BrushBlack, r1, format);
}
else
{
g.DrawString(Convert.ToString(allocation[i, j % m]), myfont, BrushBlack, r1, format);
}
}
for (int j = m; j < 3 * m; j++)
{
r1 = rectangles[q * 3 * m + j];
g.DrawRectangle(penRed, r1);
}
//finish列
Finish_Rect = new Rectangle[n];
for (int i = 0; i < n; i++)
{
Finish_Rect[i] = new Rectangle(60 + 40 * 4 * m, 40 + i * 20, 40, 20);
g.DrawRectangle(penBlack, Finish_Rect[i]);
g.DrawString(Convert.ToString(Finish[i]), myfont, BrushBlack, Finish_Rect[i], format);
}
//allocation+work列
work = new Rectangle(60 + 3 * m * 40, 40, m * 40, 20 * n);
g.DrawRectangle(penRed, work);
for (int i = 0; i < m; i++)
{
g.DrawString(Convert.ToString(Work[i]), myfont, BrushBlack, new PointF(60 + 3 * m * 40 + 40 * i, n * 1.0F / 2 * 20 + 40), format);
}
// imageList1.Images.Add(b); timerCount++;
//pictureBox1.Image = b;
// pictureBox1.Image = b;
// g.Dispose();
Graphics g2 = pictureBox1.CreateGraphics();
g2.DrawImage(b, 0, 0);
b.Dispose();
b = null;
g.Dispose();
g = null;
g2.Dispose();
g2 = null;
Thread.Sleep(3000);
}
#endregion
三、银行家算法
-
借鉴别人写的,这位做作者写的还有改进之处(效果如图3),没有展示算法过程,只安全序列,得出但关键算法思想值得借鉴与学习,且对数据的合法性给予检验,值得学习。
c#编写的操作系统作业–模拟进程调度 时间片算法
那修改后的代码如下:
#region 银行家算法
void Banker()
{
for (int i = 0; i < m; i++)
{
if (request[i] <= need[p, i])
{
if (request[ i] <= available[i])
{
available[i] -= request[i];
Work[i] = available[i];
allocation[p, i] += request[i];
need[p, i] -= request[i];
}
else
{
flag = -1;
MessageBox.Show("出错,request > available,无足够资源,无法分配!");
break;
}
}
else
{
flag = -1;
MessageBox.Show("出错,request> need,请求资源超过所需值,无法分配!");
break;
}
}
if (flag == 1) {
DrawCharts();
SafeCheck();
}else if(flag == -1)
{
tb_i.Clear();
tb_req.Clear();
}
}
#endregion
四、安全算法
-
借鉴别人写的,修改之后如下
c#编写的操作系统作业–模拟进程调度 时间片算法
void SafeCheck()
{
int[] SafeIndex = new int[n];
int SafeCount = 0;//计数当前安全序列个数
int k = n;//最大检查次数
for (int i = 0; i < m; i++)
{
Work[i] = available[i];
//MessageBox.Show(Work [i].ToString());
}
do
{
for (int j = 0; j < n; j++)
{
if (Finish[j] == false)
{
flag = 1;
for (int h = 0; h < m; h++)
{
if (need[j, h] > Work[h])
{
flag = 0;
}
}
if (flag == 1)
{
q = j;
Finish[j] = true;
SafeIndex[SafeCount++] = j;
for (int i = 0; i < m; i++)
{
Work[i] -= need[j, i];
allocation[j, i] += need[j,i];
need[j, i] = 0;
}
/*
new Thread((ThreadStart)(delegate ()
{
// 此处警惕值类型装箱造成的"性能陷阱"
pictureBox1.Invoke((MethodInvoker)delegate ()
{
DrawCharts();
});
}
)).Start();
*/
// Thread.Sleep(2000);
DrawCharts();
for (int i = 0; i < m; i++)
{
Work[i]+= allocation[j, i];
allocation[j, i] = 0;
}
/*new Thread((ThreadStart)(delegate ()
{
// 此处警惕值类型装箱造成的"性能陷阱"
pictureBox1.Invoke((MethodInvoker)delegate ()
{
DrawCharts();
});
}
)).Start();
*/
//Thread.Sleep(2000);
DrawCharts();
}
}
}
k--;
}while (k > 0);
for (int i = 0; i < n; i++)
{
if (Finish[i] == false)
{
flag = 0;
break;
}
}
if (flag == 0)
{
MessageBox.Show("分配后系统将处于不安全状态,不予分配!即将还原初值");
for (int i = 0; i < m; i++)
{
available[i] += request[i];
allocation[p, i] -= request[i];
need[p, i] += request[i];
Work[i] = available[i];
}
DrawCharts();
}
else
{
//for (int i = 0; i < n; i++)
tb_safe.Text = string.Join(" ", SafeIndex);
MessageBox.Show("资源申请成功!");
}
}
#endregion
五、 整体代码如下
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SafeBank
{
public partial class MainForm : Form
{
Pen penBlack;
Pen penRed;
Font myfont;
StringFormat format;
SolidBrush BrushBlack;
SolidBrush BrushRed;
int[,] max = new int[10, 10];
int[] available = new int[10];
int[,] allocation = new int[10, 10];
int[,] need = new int[10, 10];
int[] request = new int[10];
Rectangle[] rectangles;
Rectangle work;
Rectangle[] Finish_Rect;
int[] Work;
bool[] Finish;
int flag = 1;//有3个值,在banker函数中:{1:request合法,可以调用安全算法了。-1:request > available或request> need时置-1,用来检测request数据不合法}
//在safe函数中{0:表示分配之后不安全,1:当前进程可以分配}
int p;//请求资源的进程编号
int q;//现在正在处理的进程编号,用来画红色线框标识的部分
int m;//资源数
int n;//进程数
//int timerCount=0;
//Bitmap b;
//PictureBox pB;
string[] word = { "Max", "Need", "Allocation", "Allocation+Work", "Finish" };
String[] letters = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" };
public MainForm()
{
InitializeComponent();
penBlack = new Pen(Color.Black,1);
penRed= new Pen(Color.Red,1);
myfont = new Font("April", 10);
BrushBlack = new SolidBrush(Color.Black);
BrushRed = new SolidBrush(Color.Red);
format = new StringFormat();
//this.BackgroundImage = Image.FromFile("background5.jpg");
}
#region 界面初始化
private void Child_Load(object sender, EventArgs e)
{
}
#endregion
#region 初始化表格
void DrawCharts() {
Bitmap b = new Bitmap(1200, 600);
Graphics g = Graphics.FromImage(b);
//pB = pictureBox1;
//Graphics g = this.CreateGraphics();
//Graphics g = pictureBox1.CreateGraphics();
g.Clear(Color.White);
Rectangle r1;
//左一列
r1 = new Rectangle(0, 0, 60, 20);
g.DrawRectangle(penBlack, r1);
g.DrawString("资源情况", myfont, BrushBlack, r1, format);
r1 = new Rectangle(0, 20, 60, 20);
g.DrawRectangle(penBlack, r1);
g.DrawString("进程", myfont, BrushBlack, r1, format);
for (int i = 0; i < n; i++)
{
r1 = new Rectangle(0, i * 20 + 40, 60, 20);
g.DrawRectangle(penBlack, r1);
g.DrawString("进程 " + i, myfont, BrushBlack, r1, format);
}
//上一行
for (int i = 0; i < 4; i++)
{
r1 = new Rectangle(60 + i * (40 * m), 0, 40 * m, 20);
g.DrawRectangle(penBlack, r1);
g.DrawString(word[i], myfont, BrushBlack, r1, format);
}
r1 = new Rectangle(60 + 4 * (40 * m), 0, 40, 40);
g.DrawRectangle(penBlack, r1);
g.DrawString(word[4], myfont, BrushBlack, r1, format);
//上二行
for (int i = 0; i < 4 * m; i++)
{
r1 = new Rectangle(60 + i * 40, 20, 40, 20);
g.DrawRectangle(penBlack, r1);
//letter 里放资源名,最大10个资源A~J
g.DrawString(letters[i % m], myfont, BrushBlack, r1, format);
}
//数字区域,创建n * 3 * m个矩形数组,方便调用
rectangles = new Rectangle[n * 3 * m];
for (int i = 0; i < n; i++)
for (int j = 0; j < 3 * m; j++)
{
//画矩形
rectangles[i * 3 * m + j] = new Rectangle(j * 40 + 60, 40 + i * 20, 40, 20);
r1 = rectangles[i * 3 * m + j];
g.DrawRectangle(penBlack, r1);
//字符
if (j < m)
{
g.DrawString(Convert.ToString(max[i, j]), myfont, BrushBlack, r1, format);
}
else if (j < 2 * m)
{
g.DrawString(Convert.ToString(need[i, j % m]), myfont, BrushBlack, r1, format);
}
else
{
g.DrawString(Convert.ToString(allocation[i, j % m]), myfont, BrushBlack, r1, format);
}
}
//以下是画红框的部分,设置了全局变量q标识现在在处理的是哪个进程,默认从0进程开始,为了方便,用红色笔覆盖原来的矩形部分
for (int j = m; j < 3 * m; j++)
{
r1 = rectangles[q * 3 * m + j];
g.DrawRectangle(penRed, r1);
}
//finish列 创建n个finish列的矩阵
Finish_Rect = new Rectangle[n];
for (int i = 0; i < n; i++)
{
Finish_Rect[i] = new Rectangle(60 + 40 * 4 * m, 40 + i * 20, 40, 20);
g.DrawRectangle(penBlack, Finish_Rect[i]);
g.DrawString(Convert.ToString(Finish[i]), myfont, BrushBlack, Finish_Rect[i], format);
}
//allocation+work列
work = new Rectangle(60 + 3 * m * 40, 40, m * 40, 20 * n);
g.DrawRectangle(penRed, work);
for (int i = 0; i < m; i++)
{
g.DrawString(Convert.ToString(Work[i]), myfont, BrushBlack, new PointF(60 + 3 * m * 40 + 40 * i, n * 1.0F / 2 * 20 + 40), format);
}
// imageList1.Images.Add(b); timerCount++;
//pictureBox1.Image = b;
// pictureBox1.Image = b;
// g.Dispose();
Graphics g2 = pictureBox1.CreateGraphics();
g2.DrawImage(b, 0, 0);
b.Dispose();
b = null;
g.Dispose();
g = null;
g2.Dispose();
g2 = null;
Thread.Sleep(3000);
}
#endregion
#region 银行家算法
void Banker()
{
for (int i = 0; i < m; i++)
{
if (request[i] <= need[p, i])
{
if (request[ i] <= available[i])
{
available[i] -= request[i];
Work[i] = available[i];
allocation[p, i] += request[i];
need[p, i] -= request[i];
}
else
{
flag = -1;
MessageBox.Show("出错,request > available,无足够资源,无法分配!");
break;
}
}
else
{
flag = -1;
MessageBox.Show("出错,request> need,请求资源超过所需值,无法分配!");
break;
}
}
if (flag == 1) {
DrawCharts();
SafeCheck();
}else if(flag == -1)
{
tb_i.Clear();
tb_req.Clear();
}
}
#endregion
#region Safe
void SafeCheck()
{
int[] SafeIndex = new int[n];
int SafeCount = 0;//计数当前安全序列个数
int k = n;//最大检查次数
for (int i = 0; i < m; i++)
{
Work[i] = available[i];
//MessageBox.Show(Work [i].ToString());
}
do
{
for (int j = 0; j < n; j++)
{
if (Finish[j] == false)
{
flag = 1;
for (int h = 0; h < m; h++)
{
if (need[j, h] > Work[h])
{
flag = 0;
}
}
if (flag == 1)
{
q = j;
Finish[j] = true;
SafeIndex[SafeCount++] = j;
for (int i = 0; i < m; i++)
{
Work[i] -= need[j, i];
allocation[j, i] += need[j,i];
need[j, i] = 0;
}
/*
new Thread((ThreadStart)(delegate ()
{
// 此处警惕值类型装箱造成的"性能陷阱"
pictureBox1.Invoke((MethodInvoker)delegate ()
{
DrawCharts();
});
}
)).Start();
*/
// Thread.Sleep(2000);
DrawCharts();
for (int i = 0; i < m; i++)
{
Work[i]+= allocation[j, i];
allocation[j, i] = 0;
}
/*new Thread((ThreadStart)(delegate ()
{
// 此处警惕值类型装箱造成的"性能陷阱"
pictureBox1.Invoke((MethodInvoker)delegate ()
{
DrawCharts();
});
}
)).Start();
*/
//Thread.Sleep(2000);
DrawCharts();
}
}
}
k--;
}while (k > 0);
for (int i = 0; i < n; i++)
{
if (Finish[i] == false)
{
flag = 0;
break;
}
}
if (flag == 0)
{
MessageBox.Show("分配后系统将处于不安全状态,不予分配!即将还原初值");
for (int i = 0; i < m; i++)
{
available[i] += request[i];
allocation[p, i] -= request[i];
need[p, i] += request[i];
Work[i] = available[i];
}
DrawCharts();
}
else
{
//for (int i = 0; i < n; i++)
tb_safe.Text = string.Join(" ", SafeIndex);
MessageBox.Show("资源申请成功!");
}
}
#endregion
private void button1_Click(object sender, EventArgs e)
{
if (tb_i.Text.Trim() == "" && tb_req.Text.Trim() == "")
MessageBox.Show("请正确填写进程号和请求向量!");
else
{
p = int.Parse(tb_i.Text);
string s = tb_req.Text;
string[] r = new string[m];
r = s.Split();
for (int i = 0; i < m; i++)
request[i] = int.Parse(r[i]);
q = p;
Banker();
/*
new Thread((ThreadStart)(delegate ()
{
foreach(Bitmap bitmap in imageList1.Images)
// 此处警惕值类型装箱造成的"性能陷阱"
pictureBox1.BeginInvoke((MethodInvoker)delegate ()
{
pictureBox1.Image = bitmap;
});
})).Start();
*/
}
}
private void Child_FormClosing(object sender, FormClosingEventArgs e)
{
Application.Exit() ;
}
#region 获取数据
private void button2_Click_1(object sender, EventArgs e)
{
n = int.Parse(tb_n.Text);//进程数
m = int.Parse(tb_m.Text);//资源数 建议1~6,否则印象美观
//初始化Max
for (int i = 0; i < n; i++)
{
string lineStr = rtb_max.Lines[i];
string[] b = new string[m];
b = lineStr.Split();
int j = b.Length;
for (int k = 0; k < j; k++)
{
max[i, k] = int.Parse(b[k]);
}
}
//初始化Allocation
for (int i = 0; i < n; i++)
{
string lineStr = rtb_allo.Lines[i];
string[] b = new string[m];
b = lineStr.Split();
int j = b.Length;
for (int k = 0; k < j; k++)
{
allocation[i, k] = int.Parse(b[k]);
}
}
//初始化Need
for (int i = 0; i < n; i++)
{
string lineStr = rtb_need.Lines[i];
string[] b = new string[m];
b = lineStr.Split();
int j = b.Length;
for (int k = 0; k < j; k++)
{
need[i, k] = int.Parse(b[k]);
}
}
//初始化Avaliable
string[] s = new string[m];
string Str = rtb_aval.Lines[0];
s = Str.Split();
for (int k = 0; k < m; k++)
{
available[k] = int.Parse(s[k]);
}
//监测数据输入是否合法need[i, j] == max[i, j] - allocation[i, j]
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (need[i, j] != max[i, j] - allocation[i, j])
MessageBox.Show("输入数据不符合要求。");
}
}
Finish = new bool[n];//初始化Finish[i] =false,表示各进程都未访问过,用来表示表格中finish列的值
Work = new int[m];//初始化work[]矩阵,值为available[],因为DrawCharts()函数的work+available列的数据就是work[]的值
for (int i = 0; i < n; i++)
{
Finish[i] = false;
}
for (int i = 0; i < m; i++)
{
Work[i] = available[i];
}
DrawCharts();//初始化原始数据得到的表格
}
}
#endregion
}
六、结果展示
测试数据:
max:
1 1 1 2
2 1 2 1
1 2 1 1
2 1 0 0
allocation:
0 1 0 1
2 0 0 1
1 0 0 0
2 0 0 0
need:
1 0 1 1
0 1 2 0
0 2 1 1
0 1 0 0
avalible
1 2 2 1
进程数:4
资源数:4
Pi(请求资源的进程编号从0开始):1
Pi的需求矩阵:0 1 1 0
结果截图如下: