杭州电子科技大学
学生实验报告书
实验课程名称 《计算机操作系统》
开 课 学 院 软件工程学院
指导老师姓名 任一支
学 生 姓 名 王体方 王雁飞 谷莉莎 陆文英
学生专业班级 软件工程10108412 10108413
2012 — 2013 学年 第一学期
生产者消费者实验
实验内容:
以生产者消费者模型为依据,提供一个多线程生产者-消费者实例,用VC或java实现,并具备以下功能:
(1) 可改变缓冲区数目;
(2) 可增加或减少线程数目;
(3) 改变延迟时间;
(4) 可增加或减少生产者、消费者进程数目;
(5) 可改变消费者进程请求序列;
一、流程图:
二、源代码:
package pro_con;
publicclassMain
{
publicstaticvoid main(String[] args)
{
new Main().start();
}
public void start()
{
Buffers buffers=new Buffers(5);
String [] idList4={"5","6"};
String [] idList7={"1","3","5"};
new Pro_Thread("生产者 1",buffers,5,"1").start();
new Pro_Thread("生产者 2",buffers,4,"2").start();
new Pro_Thread("生产者 3",buffers,2,"3").start();
new Pro_Thread("生产者 5",buffers,7,"5").start();
new Pro_Thread("生产者 6",buffers,1,"6").start();
new Con_Thread("消费者 4",buffers,6,idList4).start();
new Con_Thread("消费者 7",buffers,3,idList7).start();
}
}
Buffers.java:
package pro_con;
//缓冲区
publicclassBuffers
{
privateintproductNum;//缓冲单元数目
publicstaticProductproducts[];//缓冲区队列
privateintcount=0; //记录使用的缓冲区单元
public Buffers(int productNum)
{
super();
this.productNum= productNum;
this.products=newProduct[productNum];
this.initBuffersPool();
}
//初始化该缓冲区
publicvoid initBuffersPool()
{
for (int i =0; i <products.length; i++)
{
products[i] =new Product();
products[i].setProductId("-1");
}
}
//取出产品
public synchronizedProduct get(String id)
{
Product product =null;
while(count==0)
{
try
{
super.wait();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
this.notifyAll();
int x =-1;
int i =0;
for (i =0; i <products.length; i++)
{
if(products[i].getProductId().equals(id))
{
x = i;
product =products[i];
products[i].setProductId("-1");
break;
}
}
while(i ==products.length)
{
try
{
super.wait();
for (i =0; i <products.length; i++)
{
if(products[i].getProductId() == id)
{
x = i;
product =products[i];
products[i].setProductId("-1");
break;
}
}
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
notifyAll(); System.out.println(Thread.currentThread().getName() +" 开始消费 \t" + id +"产品");
count--;
System.out.println(Thread.currentThread().getName() +" 成功消费\t"+ id +"产品\n");
System.out.println("缓冲区 ["+ x +"]\t"+products[x]+"\n");
return product;
}
//添加产品
public synchronizedboolean put(String productId)
{
boolean bool =false;
//如果满了,就等待消费者消费
while(count==products.length)
{
try{
super.wait();
}catch(Exception e){
e.printStackTrace();
}
}
this.notifyAll();
int i = findPutLocation();
System.out.println(Thread.currentThread().getName() +" 开始在\t缓冲区"
+ i +"\t生产");
bool =true;
products[i].setProductId(productId);
count++;
System.out.println(Thread.currentThread().getName() +" 完成生产\n");
System.out.println("缓冲区 ["+ i +"]\t"+products[i]+"\n");
return bool;
}
//找一个合适的位置
publicsynchronizedint findPutLocation()
{
int k =0;
for (int i =0; i <products.length; i++)
{
if(products[i].getProductId().equals("-1"))
{
k = i;
break;
}
}
return k;
}
}
Product.java:
package pro_con;
//产品
publicclassProduct
{
privateString productId;
publicString getProductId()
{
returnproductId;
}
publicvoid setProductId(String productId)
{
this.productId= productId;
}
publicString toString()
{
returnproductId;
}
}
消费者线程:
Con_Thread.java:
package pro_con;
publicclassCon_ThreadextendsThread
{
privatestaticfinalint baseTime =1000;
privateStringidList[];//消费者消费产品
privateintn;// 延迟时间
privateBuffersbuffers;
privateinti=0;
public Con_Thread(String name,Buffers buffers,int n,String idList[])
{
super(name);
this.idList= idList;
this.n= n;
this.buffers= buffers;
}
@Override
publicvoid run()
{
while (i<idList.length)
{
try
{
Thread.sleep(n* baseTime);
System.out.println(Thread.currentThread().getName() +" 请求消费\t"
+idList[i] +"产品");
buffers.get(idList[i]);
++i;
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
生产者线程:
Pro_Thread.java:
package pro_con;
publicclassPro_ThreadextendsThread
{
privatestaticfinalint baseTime =1000;
privateBuffersbuffers;
privateintn;
privateStringid;
public Pro_Thread(String name ,Buffers buffers,int n,String id)
{
super(name);
this.n= n;
this.buffers=buffers;
this.id= id;
}
@Override
publicvoid run()
{
try
{
Thread.sleep(n*baseTime);
System.out.println(Thread.currentThread().getName() +" 发出请求生产信号");
buffers.put(id);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
三、测试用例:
输出结果为:
第二篇:操作系统实验报告 经典的生产者—消费者问题
实验二 经典的生产者—消费者问题
一、目的
实现对经典的生产者—消费者问题的模拟,以便更好的理解经典进程同步问题。
二、实验内容及要求
编制生产者—消费者算法,模拟一个生产者、一个消费者,共享一个缓冲池的情形。
1、实现对经典的生产者—消费者问题的模拟,以便更好的理解此经典进程同步问题。生产者-消费者问题是典型的PV操作问题,假设系统中有一个比较大的缓冲池,生产者的任务是只要缓冲池未满就可以将生产出的产品放入其中,而消费者的任务是只要缓冲池未空就可以从缓冲池中拿走产品。缓冲池被占用时,任何进程都不能访问。
2、每一个生产者都要把自己生产的产品放入缓冲池,每个消费者从缓冲池中取走产品消费。在这种情况下,生产者消费者进程同步,因为只有通过互通消息才知道是否能存入产品或者取走产品。他们之间也存在互斥,即生产者消费者必须互斥访问缓冲池,即不能有两个以上的进程同时进行。
三、生产者和消费者原理分析
在同一个进程地址空间内执行两个线程。生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放一个空缓冲区。当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻挡,直到新的物品被生产出来。
四、生产者与消费者功能描述:
生产者功能描述:在同一个进程地址空间内执行两个线程。生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。
消费者功能描述:消费者线程从缓冲区获得物品,然后释放缓冲区,当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。
五、实验环境
操作系统环境:Windows系统。
编程语言:C#。
六、生产者与消费者的思路和设计
1、程序流程图
(1) 生产者
(2) 消费者
2、主要程序代码
//初始化变量
private void Form1_Load(object sender, EventArgs e)
{
mutex = 1; //互斥信号量
full = 0; //缓冲池中满缓冲区的数量
empty = 5;//缓冲池中空缓冲区的数量
count1 = 0;//生产的产品数目
i = 0;
lb_mutex.Text = "1";
lb_full.Text = "0";
lb_empty.Text = "5";
}
//消费者从缓冲区中消费一个产品
private void consumer_Click(object sender, EventArgs e)
{
if (full > 0)
{ //消费者已进入互斥临界区
if (mutex == 1) //申请进入临界区
{
mutex = 0; //消费者已进入互斥临界区
lb_mutex.Text = "0";
timer_consumer.Enabled = true;//启动消费者消费缓冲区产品
}
else
{
MessageBox.Show("缓冲区被占用,请等待。。。", "信息提"MessageBoxButtons.OK);
}
}
else
{
MessageBox.Show("缓冲区为空,不能消费!", "信息提示", MessageBoxButtons.OK);
}
}
//生产者向缓冲区中存入一个产品
private void producer_Click(object sender, EventArgs e)
{
count1 = count1 + 1; //生产一个产品
if (empty > 0)
{ //有缓冲区可放产品
if (mutex == 1)
{ //申请进入临界区
mutex = 0; //生产者已进入临界区
lb_mutex.Text = "0";
timer1.Start(); //启动生产者将产品放入缓冲区
}
else
{ //不能进入临界区
count1 = count1 - 1;
MessageBox.Show("缓冲区被占用,请等待。。。", "信息提示", MessageBoxButtons.OK);
}
}
else
{
MessageBox.Show("缓冲区已满!", "信息提示", MessageBoxButtons.OK); //无缓冲区可放产品
count1 = count1 - 1;
}
}
//生产者
private void timer1_Tick_1(object sender, EventArgs e)
{
if (bool1)
{
switch (count1)
{
case 1: pictureBox1.Visible = true; break;
case 2: pictureBox2.Visible = true; break;
case 3: pictureBox3.Visible = true; break;
case 4: pictureBox4.Visible = true; break;
case 5: pictureBox5.Visible = true; break;
}
lb_show.Text = "生产者进程占用缓冲区,请等待。。。。";
bool1 = false;
}
else
{
switch (count1)
{
case 1: pictureBox1.Visible = false; break;
case 2: pictureBox2.Visible = false; break;
case 3: pictureBox3.Visible = false; break;
case 4: pictureBox4.Visible = false; break;
case 5: pictureBox5.Visible = false; break;
}
lb_show.Text = "生产者进程占用缓冲区,请等待。。。。";
bool1 = true;
}
i = i + 1;
if (i == 5)
{ //循环缓冲区,首尾相接
i = 0;
timer1.Enabled = false;
mutex = 1;
lb_mutex.Text = "1";
switch (count1)
{
case 1: pictureBox1.Visible = true; break;
case 2: pictureBox2.Visible = true; break;
case 3: pictureBox3.Visible = true; break;
case 4: pictureBox4.Visible = true; break;
case 5: pictureBox5.Visible = true; break;
}
full = full + 1;
lb_full.Text = full.ToString();
empty = empty - 1;
lb_empty.Text = empty.ToString();
lb_show.Text = "生产结束!";
}
}
//消费者
private void timer_consumer_Tick(object sender, EventArgs e)
{
if(bool1){
switch(count1){
case 1: pictureBox1.Visible = true; break;
case 2: pictureBox2.Visible = true; break;
case 3: pictureBox3.Visible = true; break;
case 4: pictureBox4.Visible = true; break;
case 5: pictureBox5.Visible = true; break;
}
lb_show.Text = "消费者进程占用缓冲区,请等待。。。。";
bool1 =false;
}
else{
switch(count1){
case 1: pictureBox1.Visible = false; break;
case 2: pictureBox2.Visible = false; break;
case 3: pictureBox3.Visible = false; break;
case 4: pictureBox4.Visible = false; break;
case 5: pictureBox5.Visible = false; break;
}
lb_show.Text= "消费者进程占用缓冲区,请等待。。。。";
bool1= true;
}
i = i + 1;
if(i==5){
i = 0;
timer_consumer.Enabled = false;
mutex = 1;
lb_mutex.Text= "1";
switch(count1){
case 1: pictureBox1.Visible = false; break;
case 2: pictureBox2.Visible = false; break;
case 3: pictureBox3.Visible = false; break;
case 4: pictureBox4.Visible = false; break;
case 5: pictureBox5.Visible = false; break;
}
count1 = count1 - 1;
full = full - 1;
lb_full.Text = full.ToString();
empty = empty+1;
lb_empty.Text=empty.ToString();
lb_show.Text="消费结束!";
}
3、运行界面和运行结果
一般情况下,点一次生产者按纽,mutex由1变为0,缓冲区呈现闪烁状态(表示正在存储),此时不可以再进行缓冲区操作,否则将显示“生产者进程正在占用缓冲区,请等待”。闪烁约1.5秒后,mutex由0变为1,闪烁停止,表示存储过程结束;点一次消费者按纽,mutex由1变为0,缓冲区呈现闪烁状态(表示正在消费),此时不可以再进行缓冲区操作,否则将显示“消费者进程正在占用缓冲区,请等待”。闪烁约1.5秒后,mutex由0变为1,闪烁停止,表示消费过程结束。
缓冲池满后,若再点生产者按纽,会给出信息提示:“缓冲区已满!”。
缓冲池空后,若再点消费者按纽,也会给出信息提示:“缓冲区为空,不能消费!”。
在存储状态或消费状态(闪烁状态),无论是点生产者按纽还是消费者按纽都会给出“缓冲区被占用,请等待。。”信息提示。
七、心得体会
本次实验是关于生产者与消费者之间互斥和同步的问题。问题的是指是P、V操作,实验设一个共享缓冲区,生产者和消费者互斥的使用,当一个线程使用缓冲区的时候,另一个让其等待直到前一个线程释放缓冲区为止。
生产者与消费者是一个与现实有关的经验问题,通过此原理举一反三可以解决其他类似的问题。
通过本实验设计,我们对操作系统的P、V进一步的认识,深入的了解P、V操作的实质和其重要性。课本的理论知识进一步阐述了现实中的实际问题。
实验中,我们小组分工合作,共同学习,虽然在实验中遇到了一些问题,但在老师和同学的细心指导和热心帮助下解决了。同时,了解到团队精神的重要性,也为以后的学习和工作打下了坚实的基础,同时积累了宝贵的经验。