C#窗体模拟生产者消费者问题
Posted nepu_hua
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#窗体模拟生产者消费者问题相关的知识,希望对你有一定的参考价值。
模拟内容
1、实现对经典的生产者—消费者问题的模拟,以便更好的理解此经典进程同步问题。生产者-消费者问题是著名的进程同步问题。它描述一组生产者向一组消费者提供产品,它们共享一个有界缓冲池,生产者的任务是向其中投放产品,消费者从中取得产品。
2、假定生产者和消费者是互相等效的,只要缓冲池未满,生产者就可以将生产出的产品放入其中;而只要缓冲池未空,消费者就可以从缓冲池中拿走产品。
3、生产者消费者进程同步,因为只有通过互通消息才知道是否能存入产品或者取走产品。他们之间也存在互斥,缓冲池被占用时,任何进程都不能访问,即生产者、消费者必须互斥访问缓冲池。
模拟思路
1、随机产生每个生产者生产一个产品的时间和每个消费者消费一个产品的时间,并显示出来。
2、随着时间的推移,体现生产者生产一个产品的过程和消费者消费一个产品的过程,并统计出生产产品的总数和消费产品的总数。
3、限制缓冲池中缓冲区的容量,如只能容纳N个产品。当缓冲池已满时,要能够体现出生产者处于等待的情形;当缓冲区为空时,要能够体现出消费者处于等待的情形。
实现方法
使用random类的对象产生随机数随机生成生产者和消费者的生产和消费时间,采用线程的sleep函数让当前正在运行线程挂起模拟生产者或消费者生产或消费的过程,采用c#窗体中的timer定时器控件动态显示当前系统时间。
编程实现
初始化一些全局变量,包括随机生成的生产时间和消费时间,生产总数,消费总数,循环队列左右指针,互斥量等。
public Form1()
{
InitializeComponent();
Random ra = new Random();
timep = ra.Next(1, 10);//随机产生1-10的生产时间
timec = ra.Next(1, 10);//随机产生1-10的消费时间
this.lbptime.Text = "单位生产时间:" + timep.ToString() + "秒";
this.lbctime.Text = "单位消费时间:" + timec.ToString() + "秒";
}
int countp = 0;//生产总数
int countc = 0;//消费总数
int left = 0;//左指针
int right = 0;//右指针
int timep = 0;//生产时间
int timec = 0;//消费时间
int mutex = 1;//互斥量
int empty = 5;//空缓冲区的个数
int full = 0;//有产品的缓冲区的个数
消费者线程
void consumer() {
if (full > 0)
{
if (mutex == 1)
{
mutex = 0;
this.lbm.Text = "mutex:" + mutex.ToString();
consume(left);
left = (left + 1) % 5;
countc++;
this.lbc.Text = "消费总数:" + countc.ToString();
full--;
empty++;
this.lbf.Text = "full:" + full.ToString();
this.lbe.Text = "empty:" + empty.ToString();
mutex = 1;
this.lbm.Text = "mutex:" + mutex.ToString();
}
else
{
this.lbts1.Text = "缓冲区已被占用,请等待....";
}
}
else
{
this.lbts1.Text = "缓冲区为空,不能消费,请等待....";
}
}
生产者线程函数。
void productor() {
if (empty > 0)//判断缓冲区是否已满
{
if (mutex == 1)
{
mutex = 0;
this.lbm.Text = "mutex:" + mutex.ToString();
product(right);//调用方法生产商品
right = (right + 1) % 5;
countp++;//统计生产个数
this.lbp.Text = "生产总数:" + countp.ToString();
empty--;
full++;
this.lbf.Text = "full:" + full.ToString();
this.lbe.Text = "empty:" + empty.ToString();
mutex = 1;
this.lbm.Text = "mutex:" + mutex.ToString();
}
else
{
this.lbts1.Text = "缓冲区已被占用,请等待....";
}
}
else
{
this.lbts1.Text = "缓冲区已满,不能生产,请等待....";
}
}
编写函数用于修改消费者消费指定的缓存区的颜色并维持指定的时间。
public void consume(int index) {
Form1 f = new Form1();
switch (index) {
case 0: this.b1.BackColor = Color.Red; Thread.Sleep(timec * 1000); this.b1.BackColor = Color.White; this.lbts1.Text = "就绪!"; break;
case 1: this.b2.BackColor = Color.Red; Thread.Sleep(timec * 1000); this.b2.BackColor = Color.White; this.lbts1.Text = "就绪!"; break;
case 2: this.b3.BackColor = Color.Red; Thread.Sleep(timec * 1000); this.b3.BackColor = Color.White; this.lbts1.Text = "就绪!"; break;
case 3: this.b4.BackColor = Color.Red; Thread.Sleep(timec * 1000); this.b4.BackColor = Color.White; this.lbts1.Text = "就绪!"; break;
case 4: this.b5.BackColor = Color.Red; Thread.Sleep(timec * 1000); this.b5.BackColor = Color.White; this.lbts1.Text = "就绪!"; break;
}
}
编写函数用于修改生产者生产对应的缓存区的颜色并维持指定的时间。
public void product(int index)
{
Form1 f = new Form1();
switch (index)
{
case 0: this.b1.BackColor = Color.Red; Thread.Sleep(timep * 1000); this.b1.BackColor = Color.LawnGreen; this.lbts1.Text = "就绪!"; break;
case 1: this.b2.BackColor = Color.Red; Thread.Sleep(timep * 1000); this.b2.BackColor = Color.LawnGreen; this.lbts1.Text = "就绪!"; break;
case 2: this.b3.BackColor = Color.Red; Thread.Sleep(timep * 1000); this.b3.BackColor = Color.LawnGreen; this.lbts1.Text = "就绪!"; break;
case 3: this.b4.BackColor = Color.Red; Thread.Sleep(timep * 1000); this.b4.BackColor = Color.LawnGreen; this.lbts1.Text = "就绪!"; break;
case 4: this.b5.BackColor = Color.Red; Thread.Sleep(timep * 1000); this.b5.BackColor = Color.LawnGreen; this.lbts1.Text = "就绪!"; break;
}
}
生产按钮对应的后台代码,创建线程调用对应的线程函数。
private void button6_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(productor));
t.Start();
}
消费按钮对应的后台代码,创建线程调用对应的线程函数。
private void button7_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(this.consumer));
t.Start();
}
通过C#中的timer控价实现在窗体中动态显示系统时间。
private void Form1_Load(object sender, EventArgs e) //首先在主窗体添加定时事件
{
this.timer1.Interval = 1000;//设置定时器触发间隔
this.timer1.Start(); //启动定时器
this.lbtime.Text = DateTime.Now.ToString();
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
}
private void timer1_Tick(object sender, EventArgs e) //接着在定时器触发事件中添加获取时间和显示时间函数
{
DateTime time = DateTime.Now; //获取当前时间
lbtime.Font = new Font("宋体", 15); //设置label1显示字体
this.lbtime.Text = time.ToString(); //显示当前时间
}
运行结果
进入系统的初始页面如图所示。
在初始页面点击生产,缓冲区变为红色表示生产者正在生产,如图所示,一段时间后缓冲区变为绿色表示生产完成,如图所示。
当缓冲区为空时点击消费按钮系统提示缓冲区为空,不能消费,请等待,如图所示。
当缓冲区已满时点击生产按钮系统提示缓冲区已满,不能生产,请等待,如图所示。
当生产处于生产的过程中时点击消费或消费者在消费时点击生产系统提示缓冲区已被占用,请等待,如图所示。
以上是关于C#窗体模拟生产者消费者问题的主要内容,如果未能解决你的问题,请参考以下文章
SpringCloud系列十一:SpringCloudStream(SpringCloudStream 简介创建消息生产者创建消息消费者自定义消息通道分组与持久化设置 RoutingKey)(代码片段