操作系统生产者消费者缓冲池与区的问题.docx
《操作系统生产者消费者缓冲池与区的问题.docx》由会员分享,可在线阅读,更多相关《操作系统生产者消费者缓冲池与区的问题.docx(21页珍藏版)》请在冰豆网上搜索。
操作系统生产者消费者缓冲池与区的问题
一个生产者一个消费者对应一个缓冲区;
源程序:
我用的是java语言。
。
。
importjava.lang.Math;
publicclassAProBuffCon//加互斥锁的缓冲区
{
privateintvalue;//共享变量
privatebooleanisEmpty=true;//value是否为空的信号量
publicsynchronizedvoidput(inti)//同步方法
{
while(!
isEmpty)//当value不空时,等待
try
{
this.wait();//使调用该方法的当前线程等待,即阻塞自己
}
catch(InterruptedExceptione){}
value=i;//当value空时,value获得值
System.out.println(Thread.currentThread().getName()+"Producerput:
"+value);
isEmpty=false;//设置value为不空状态
notifyAll();//唤醒其他所有等待线程
}
publicsynchronizedintget()//同步方法
{
while(isEmpty)//当value空时,等待
try
{
this.wait();
}
catch(InterruptedExceptione){}
isEmpty=true;//设置value为空状态,并返回值
notifyAll();//唤醒其他所有等待线程
returnvalue;
}
publicstaticvoidmain(Stringargs[])
{
AProBuffConbuffer=newAProBuffCon();
(newProducered(buffer)).start();//构造两个生产者线程和两个消费者线程
(newConsumered(buffer)).start();
}
}
classProduceredextendsThread//生产者
{
privateAProBuffConbuffer;
publicProducered(AProBuffConbuffer)
{
this.buffer=buffer;
}
publicvoidrun()
{
//for(inti=1;i<=10;i++)
//{
intj=(int)(Math.random()*10);
buffer.put(j);
//}
}
}
classConsumeredextendsThread//消费者
{
privateAProBuffConbuffer;
publicConsumered(AProBuffConbuffer)
{
this.buffer=buffer;
}
publicvoidrun()
{
//for(inti=1;i<=10;i++)//消费者从缓冲区中取数
System.out.println("\t\t\t\t"+Thread.currentThread().getName()+"Consumerget:
"+buffer.get());
}
}
说明:
都是先生产在消费。
多个生产者多个消费者对应一个缓冲区
源程序:
importjava.lang.Math;
publicclassAProBuffCon//加互斥锁的缓冲区
{
privateintvalue;//共享变量
privatebooleanisEmpty=true;//value是否为空的信号量
publicsynchronizedvoidput(inti)//同步方法,synchronized保证一段时间内只有一个对象访问这段程序
{
while(!
isEmpty)//当value不空时,等待
try
{
this.wait();//使调用该方法的当前线程等待,即阻塞自己
}
catch(InterruptedExceptione){}
value=i;//当value空时,value获得值
System.out.println(Thread.currentThread().getName()+"生产了:
"+value);
isEmpty=false;//设置value为不空状态
notifyAll();//唤醒其他所有等待线程
}
publicsynchronizedvoidget()//同步方法,这个成为了事实上的消费者,因为如果在外部消费,信号量不好传递
{
while(isEmpty)//当value空时,等待
try
{
this.wait();
}
catch(InterruptedExceptione){}
isEmpty=true;//设置value为空状态,并返回值
System.out.println("\t\t\t\t"+Thread.currentThread().getName()+"消费了"+value);
notifyAll();//唤醒其他所有等待线程
}
publicstaticvoidmain(Stringargs[])
{
AProBuffConbuffer=newAProBuffCon();
(newProducered(buffer)).start();
(newConsumered(buffer)).start();
(newProducered(buffer)).start();
(newConsumered(buffer)).start();
(newProducered(buffer)).start();
(newConsumered(buffer)).start();
(newProducered(buffer)).start();
(newConsumered(buffer)).start();
}
}
classProduceredextendsThread//生产者
{
privateAProBuffConbuffer;
publicProducered(AProBuffConbuffer)
{
this.buffer=buffer;
}
publicvoidrun()
{
intj=(int)(Math.random()*10);
buffer.put(j);
}
}
classConsumeredextendsThread//消费者
{
privateAProBuffConbuffer;
publicConsumered(AProBuffConbuffer)
{
this.buffer=buffer;
}
publicvoidrun()
{
buffer.get();
}
}
一个消费者一个生产者一个缓冲池
源程序及注释
importjava.lang.Math;
publicclassAProBuffCon//加互斥锁的缓冲区
{
privateintvalue[]=newint[10];//共享缓冲池
privateintin=0;//设置开关锁in标志向缓冲池生产数据,out标志消费缓冲池的数据
privateintout=0;
publicsynchronizedvoidput(inti)//同步方法,实际上向缓冲池生产数据,synchronized保证一段时间内只有一个对象访问这段程序
{
while((in+1)%10==out)//当缓冲池满时,等待
try
{
this.wait();//使调用该方法的当前线程等待,即阻塞自己
}
catch(InterruptedExceptione){}//trycatch语句,没什么意义
value[in]=i;//当缓冲池不满时,可以生产数据
System.out.println(Thread.currentThread().getName()+"在"+in+"号缓冲区"+"生产了:
"+value[in]);
in=(in+1)%10;//生产好数据后,in向后移动一位
notifyAll();//唤醒其他所有等待线程
}
publicsynchronizedvoidget()//同步方法,这个成为了事实上的消费者,因为如果在外部消费,信号量不好传递
{
while(in==out)//缓冲池为空时,等待
try
{
this.wait();
}
catch(InterruptedExceptione){}
System.out.println("\t\t\t\t"+Thread.currentThread().getName()+"消费了"+out+"号缓冲区数据:
"+value[out]);
out=(out+1)%10;//消费完数据,out后移一位
notifyAll();//唤醒其他所有等待线程
}
publicstaticvoidmain(Stringargs[])//主方法,产生一个消费者,一个生产者
{
AProBuffConbuffer=newAProBuffCon();
(newProducered(buffer)).start();//start()方法标志线程活过来了
(newConsumered(buffer)).start();
}
}
classProduceredextendsThread//名义上的生产者线程
{
privateAProBuffConbuffer;
publicProducered(AProBuffConbuffer)
{
this.buffer=buffer;
}
publicvoidrun()
{
for(inti=1;i<=20;i++)
{
intj=(int)(Math.random()*10);
buffer.put(j);
}
}
}
classConsumeredextendsThread//消费者
{
privateAProBuffConbuffer;
publicConsumered(AProBuffConbuffer)
{
this.buffer=buffer;
}
publicvoidrun()
{
for(inti=1;i<=20;i++)
buffer.get();
}
}
多个生产者多个消费者一个缓冲池
源程序:
importjava.lang.Math;
publicclassAProBuffCon//加互斥锁的缓冲区
{
privateintvalue[]=newint[10];//共享缓冲池
privateintin=0;//设置开关锁in标志向缓冲池生产数据,out标志消费缓冲池的数据
privateintout=0;
publicsynchronizedvoidput(inti)//同步方法,实际上向缓冲池生产数据,synchronized保证一段时间内只有一个对
象访问这段程序
{
while((in+1)%10==out)//当缓冲池满时,等待
try
{
this.wait();//使调用该方法的当前线程等待,即阻塞自己
}
catch(InterruptedExceptione){}//trycatch语句,没什么意义
value[in]=i;//当缓冲池不满时,可以生产数据
System.out.println(Thread.currentThread().getName()+"在"+in+"号缓冲区"+"生产了:
"+value[in]);
in=(in+1)%10;//生产好数据后,in向后移动一位
notifyAll();//唤醒其他所有等待线程
}
publicsynchronizedvoidget()//同步方法,这个成为了事实上的消费者,因为如果在外部消费,信号量不好传递
{
while(in==out)//缓冲池为空时,等待
try
{
this.wait();
}
catch(InterruptedExceptione){}
System.out.println("\t\t\t\t"+Thread.currentThread().getName()+"消费了"+out+"号缓冲区数据:
"+value[out]);
out=(out+1)%10;//消费完数据,out后移一位
notifyAll();//唤醒其他所有等待线程
}
publicstaticvoidmain(Stringargs[])//主方法,产生一个消费者,一个生产者
{
AProBuffConbuffer=newAProBuffCon();
(newProducered(buffer)).start();//start()方法标志线程活过来了
(newConsumered(buffer)).start();
(newProducered(buffer)).start();//start()方法标志线程活过来了
(newConsumered(buffer)).start();
(newProducered(buffer)).start();//start()方法标志线程活过来了
(newConsumered(buffer)).start();
}
}
classProduceredextendsThread//名义上的生产者线程
{
privateAProBuffConbuffer;
publicProducered(AProBuffConbuffer)
{
this.buffer=buffer;
}
publicvoidrun()
{
for(inti=1;i<=11;i++)
{
intj=(int)(Math.random()*10);
buffer.put(j);
}
}
}
classConsumeredextendsThread//消费者
{
privateAProBuffConbuffer;
publicConsumered(AProBuffConbuffer)
{
this.buffer=buffer;
}
publicvoidrun()
{
for(inti=1;i<=11;i++)
buffer.get();
}
}
为什么wait()和signal()一定得是原语?
wait()与signal()一定是原语,不能分开分析:
假设有下面一个关系:
S1
aa
S2S3
前提:
我们把S1当成是生产者,S2和S3为竞争的消费者,正常情况下,他们两个只能有一个来对S1生产的数据进行消费
当把wait()和signal()当做原语时程序可以写为:
Vara:
semaphore=0;
Begin
Parbegin
1.BeginS1;signal(a);end;
2.Beginwait(a);S2;end;
3.Beginwait(a);S3;end;
Parend
End
当把wait()和signal()分开来写时:
Vara:
semaphore=0;
Begin
Parbegin
1.BeginS1;a=a+1;end;
2.Beginwhile(a<=0)no-op;
A
a=a-1;
S2;end;
3.Beginwhile(a<=0)no-op;
B
a=a-1;
S3;end;
Parend
End
当是原语时,到底是哪个进程在执行,这个只有CPU知道,但是,我们可以确定,进程2或3要运行,必须等进程1生产完之后产生信号量a;而且,这样可以确定,2进程和3进程只有一个能对数据进行消费,因为一旦原语不可分,一旦进入之后,就进行a-1操作,a=0就锁住了;
当它们不是原语时,我们假设:
a此时已经就是1了。
当a进入进程2时,通过了所谓的身份验证即就是把while(a<=0)这一步已经过去,到达A这一步,注意此时a=1,因为不是原语,可以跳出,CPU调用线程3,也通过了验证,然后到达B并且继续向下执行,直到进程3的消费结束,此时,CPU回到A的断点,继续执行,接着就会发生错误,因为已经没有可供消费的数据,产生错误,当然例子还有很多,我们把时间也给其他科目花一些吧,举这样。
。
。