读者与写者操作系统课程设计实验报告.docx
《读者与写者操作系统课程设计实验报告.docx》由会员分享,可在线阅读,更多相关《读者与写者操作系统课程设计实验报告.docx(22页珍藏版)》请在冰豆网上搜索。
读者与写者操作系统课程设计实验报告
操作系统课程设计
题目名称:
读者与写者
问题描述................................................3~4
系统设计................................................5~9
源代码清单.............................................9~19
运行结果测试与分析.......................................20
总结与心得...............................................20
一、问题描述
读者与写者问题主要是涉及到操作系统中的进程同步、互斥以及信号量机制的概念,可以有多个读者进程同时进行,但是当写者进程到来时,所有的读者进程都要进入等待状态,而且写者进程只能独立。
实现读者与写者的总体思路是使用多线程,每当一个读者到来时,如果当前没有写者进程正在进行,那么立即开启一个读者线程,如果当前有写者正在进行,那么此读者应当进入等待状态,直到写者进程完成,每当一个写者到来时,若此时有读者正在进行,那么立即将正在进行的读者设置为等待状态,开启写者进程,并且当下一个写者到来时,只能进入等待状态,除非当前写者完成。
进程同步与互斥:
进程互斥是多处理机系统中的典型间接作用,通常是两个或两个以上进程需要同时访问某个共享变量,在这个程序中此共享变量就是共享文件。
我们一般将发生能够共享变量的程序段称为临界区。
两个进程不能同时进入临界区,否那么就会导致数据的不一致,产生与时间有关的错误。
我们解决互斥问题时要遵循互斥和公平两个原那么,即任意时刻只允许一个进程进入临界区,且不能让任意进程进入无限的等待。
进程同步是进程之间的直接作用。
简单的理解就是,若有两个进程A,B,若只有当A进程完成后B进程才能够启动,那么说A进程与B进程是同步的。
实现同步与互斥有多种机制,比如信号量、管程、会合、分布式系统,在这个程序中简单的用信号量来实现。
信号量
信号量机制是荷兰学者Dijkstra于1955提出的一种解决进程同步与互斥的有效工具在此机制中,信号量S是一个整数,S大于等于零代表可供并发进程使用的资源数,当S小于零时表示正在等待使用临界区的进程数。
Dijkstra同时提出了对信号量操作的PV原语:
P原语操作动作:
(1)、S减一;
(2)、若S减一后仍大于或等于零,那么进程继续进行。
(3)、若S减一小于零,那么进程被阻塞后进入与该信号量相对应的队列中,然后转进程调度。
V原语操作动作:
(1)、S加一;
(2)、若S加一后结果大于零,那么进程继续;
(3)、若S加一后结果小于或等于零,那么从该信号的等待队列中唤醒一等待进程再返回原进程继续执行或转向进程调度。
PV操作对于每一个进程来说,都只能进行一次,而且必须成对使用。
在PV执行期间不允许有中断发生。
信号量机制分整型信号量机制、记录型信号量机制、and型信号量机制以及信号量集,在这个程序中使用的是整型信号量机制。
假设共享文件是一个JTextArea,在这个JTextArea中,可以向其写入文件,也可以从其中读取文件,遵循的原那么是,多个读者可以同时进行,但写者只能单独进行,而且写者优先。
当一个读者到来时,先判断有无写者正在进行,可用一个布尔变量bwrite,当其为true时表示有写者正在进行,表示此时来到的读者只能进入等待状态。
当其为false时,表示暂无写者正在进行,来到的读者可以立即开启。
读者到来:
空闲情况下,直接开启一个读者,就是将共享文件中的内容简单的读取出,并且显示在相应读者的显示框中。
当有读者正在进行时,由于多个读者可以同时进行,因此这种情况下也是立即开启一个读者进程,同时读取。
当有写者正在进行时,由于写者优先,因此到来的读者必须进入等待状态,直到所有写者进程全部完成。
一段时间后,这个读者应当完成,并且要释放资源,即共享文件的被引用次数减一。
写者到来:
空闲情况下,直接开启一个写者,由于写者只能单独进行,因此开启一个写者后要将共享区锁住,禁止其他读者或者写者进入。
若此前有读者正在进行,那么正在进行的读者马上进入等待状态,进入等待队列,立即将此写者开启,直到该写者完成,在从等待队列中拿出处于等待的读者继续。
若此前有写者正在进行,那么刚到的这个写者要进入等待队列。
而且若后面还有读者到来,那么当前写者完成后,要先判断写者等待队列是否为空,若写者等待队列为非空,那么应先唤醒处于等待状态的写者,直到写者等待队列为空,再去唤醒处于等待状态的读者。
这里要用到两个队列:
读者等待队列,写者等待队列。
产生java.lang.IllegalMonitorStateException异常:
原因是没有注意notify(),notifyAll(),wait()方法的使用条件,如果当前的线程不是此对象锁的所有者,却调用该对象的notify(),notifyAll(),wait()方法。
解决方法是在调用wait()的方法前加上synchronized。
Synchronized:
用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行改代码段。
一、当两个并发线程访问同一个对象Object中的这个synchronize(this)同步代码块时,一个时间内只能有一个线程得到执行,另一个线程必须等待当前线程执行完这个代码块以后才能执行改代码块。
二、一个线程访问Object的一个synchronize(this)同步代码块时,另一个线程任然可以访问该object中的非synchronize(this)同步代码块。
三、当一个线程访问object的一个synchronize(this)同步代码块时,其他线程对object中所有其他synchronize(this)同步代码块的访问将被阻塞。
二、系统设计
对于该程序的设计,总共设计三个类,Reader、Writer、ReaderWriter,其中读者与写者分别实现Runnable接口,每个读者以及每个写者对应一个线程每当读者到来时,开启一个线程来处理。
packageMyWork311;
importjavax.swing.JTextArea;
//读者类,要传入一个整形参数,表是读者的序号,
//主要是实现Runnable接口
publicclassReaderimplementsRunnable{
privateintindex;//表示读者的序号
privateJTextAreaFile,noteArea,jta;//分别表示共享文件、通知栏、该读者对应的显示框,都由构造函数传入
privateStringcontent;//表示读者要读取的内容
privatestaticintcount=0;//记录读者数量
Thread[]t;
publicstaticintgetCount(){
returncount;
}
/**
*构造函数,传入必要的参数
*
*@paramindex表示读者对应的序号
*@paramFile表示共享文件栏
*@paramnoteArea表示同时栏
*@paramjta表示该读者对应的显示框
*/
publicReader(Thread[]t,intindex,JTextAreaFile,JTextAreanoteArea,
JTextAreajta){
this.t=t;
this.index=index;
thisFile=File;
this.noteArea=noteArea;
this.jta=jta;
}
publicsynchronizedvoidread(){
count++;
noteArea.append("读者"+index+"到来......\n");
content=File.getText();//获取内容
char[]c=content.toCharArray();//
Stringstr=jta.getText();//显示框中已有的内容
for(intk=str.length();kjta.append(""+c[k]);
try{
wait(1000);//等待1秒
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
publicsynchronizedvoidendRead(){
count--;
noteArea.append("读者"+index+"完成......\n");
t[index]=null;
if(t[3]!
=null){
t[3].start();
}elseif(t[4]!
=null){
t[4].start();
}elseif(t[5]!
=null){
t[5].start();
}
}
publicvoidrun(){
read();
endRead();
}
}
Writer类,每当一个写者到来时,改变共享文件
packageMyWork311;
importjavax.swing.JTextArea;
//写者类
publicclassWriteimplementsRunnable{
privateintindex;//表示写者的序号
privatestaticbooleanwrite=false;//当write=true时,表示有写者正在进行
privateJTextAreaFile,noteArea,jta;//分别表示共享文件、通知栏、该写者对应的显示框,都由构造函数传入
privateStringcontent;//表示写者要写入的内容
privatestaticintmatu=1;
privateThread[]t;
publicstaticintgetMatu(){
returnmatu;
}
publicstaticbooleanisWrite(){
returnwrite;//返回TRUE时表示有写者正在写
}
/**
*构造函数,出入必要的参数
*@paramindex表示写者的序号
*@paramFile表示共享文件
*@paramnoteArea表示通知栏
*@paramjta表示写者对应的显示框
*/
publicWrite(Thread[]t,intindex,JTextAreaFile,JTextAreanoteArea,JTextAreajta){
this.t=t;
this.index=index;
thisFile=File;
this.noteArea=noteArea;
this.jta=jta;
}
publicsynchronizedvoidwrite(){
matu--;
noteArea.append("写者"+index+"到来.....\n");
write=true;
content=jta.getText();//获取要写入的内容
char[]c=content.toCharArray();
for(intk=0;kFile.append(""+c[k]);
try{
wait(1000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
publicsynchronizedvoidendWrite(){
write=false;//表示写完成
noteArea.append("写者"+index+"完成......\n");
t[index+3]=null;
if(t[index+4]!
=null){
t[index+4].start();
}elseif(t[0]!
=null||t[1]!
=null||t[2]!
=null){
if(t[0]!
=null)
t[0].start();
if(t[1]!
=null)
t[1].start();
if(t[2]!
=null)
t[2].start();
}
matu++;
notifyAll();
}
publicvoidrun(){
write();
endWrite();
}
}
三、源代码清单
packageMyWork311;
importjava.awt.Color;
importjava.awt.Container;
importjava.awt.event.ActionEvent;
importjava.awt.event.ActionListener;
importjava.util.Collection;
importjava.util.Iterator;
importjava.util.Queue;
importjavax.swing.ImageIcon;
importjavax.swing.utton;
importjavax.swing.JFrame;
importjavax.swing.JLabel;
importjavax.swing.JScrollPane;
importjavax.swing.JTextArea;
//读者与写者界面
publicclassReaderWriterextendsJFrameimplementsActionListener{
privateImageIconim1,im2;
privateJLabeljl1=newJLabel("共享文件:
");
privateContainercon=this.getContentPane();//获取容器,所有的组件加在这个容器上
privateJTextAreaFile=newJTextArea();//共享文件显示区
privateJTextAreanoteArea=newJTextArea();//通知显示区
privateutton[]=newutton[6];//开启按钮,三个读者三个写者
privateJTextArea[]jta=newJTextArea[6];//6个显示区
privateJLabel[]jl=newJLabel[6];//读者写者标志数组
privateReader[]list1=newReader[3];
privateWrite[]list2=newWrite[3];
Threadt[]=newThread[6];
/**
*@paramargs
*/
publicstaticvoidmain(String[]args){
newReaderWriter();
}
publicReaderWriter(){
im1=newImageIcon(this.getClass().getResource("开始.JPG"));
im2=newImageIcon(this.getClass().getResource("暂停.JPG"));
this.setTitle("读者与写者问题");
this.setSize(800,600);
this.setDefaultCloseOperation(3);
this.setLocationRelativeTo(null);
con.setBackground(newColor(142,142,92));
con.setLayout(null);
con.add(jl1);//添加“共享文件”标志
jl1.setBounds(10,2,60,20);
con.add(File);//添加共享文件的显示区
File.setBounds(10,25,760,150);
File.setLineWrap(true);
JScrollPanejsp=newJScrollPane(File);
jsp.setBounds(10,25,760,150);
con.add(jsp);
//File.setEditable(false);//不可编辑
for(inti=0;i<.length;i++){//读者写者按钮以及读者写者显示区
[i]=newutton(im1);
[i].addActionListener(this);//给按钮添加监听器
[i].setActionmand(""+i);
jta[i]=newJTextArea();
con.add([i]);
con.add(jta[i]);
[i].setBounds(10,200+i*30,30,20);
jta[i].setBounds(100,200+i*30,670,20);
}
for(inti=0;i<3;i++){
jl[i]=newJLabel("读者"+i);
con.add(jl[i]);
jl[i].setBounds(50,200+i*30,50,20);
}
for(inti=3;i<6;i++){
jl[i]=newJLabel("写者"+(i-3));
con.add(jl[i]);
jl[i].setBounds(50,200+i*30,50,20);
}
con.add(noteArea);//添加通知栏
noteArea.setBounds(10,380,760,170);
noteArea.setEditable(false);
noteArea.setBackground(newColor(170,170,145));
noteArea.setLineWrap(true);
JScrollPanejs2=newJScrollPane(noteArea);
js2.setBounds(10,380,760,170);
con.add(js2);
this.setVisible(true);
}
//动作监听器,监听按钮
publicvoidactionPerformed(ActionEvente){
Stringstr=e.getActionmand();//获取监听源
if(str.equals("0")){//启动读者0,此处要启动一个对应的线程来处理对应的读者
[0].setIcon(im2);
Readerr=newReader(t,0,File,noteArea,jta[0]);
t[0]=newThread(r);
if(list2[0]==null&&Write.getMatu()==1){//表示当前没有写者正在进行且读者等待队列为空,可以立即开启一个读者
t[0].start();
}else{//表示当前有写者正在进行
for(intm=0;mif(list1[m]==null){
list1[m]=r;//将到来的读者放入等待队列中
noteArea.append("读者0到来,进入等待队列...\n");
break;
}
}
}
}elseif(str.equals("1")){//启动读者0,此处要启动一个对应的线程来处理对应的读者
[1].setIcon(im2);
Readerr=newReader(t,1,File,noteArea,jta[1]);
t[1]=newThread(r);
if(list2[0]==null){//表示当前没有读者正在进行且读者等待队列为空,可以立即开启一个读者
t[1].start();
}else{//表示当前有写者正在进行
for(intm=0;mif(list1[m]==null){
list1[m]=r;//将到来的读者放入等待队列中
noteArea.append("读者1到来,进入等待队列...\n");
break;
}
}
}
}elseif(str.equals("2")){//启动读者0,此处要启动一个对应的线程来处理对应的读者
[2].setIcon(im2);
Readerr=newReader(t,2,File,noteArea,jta[2]);
t[2]=newThread(r);
if(list2[0]==null){//表示当前没有读者正在进行且读者等待队列为空,可以立即开启一个读者
t[2].start();
noteArea.append("读者2开启...\n");
}else{//表示当前有写者正在进行
for(intm=0;mif(list1[m]==null){
list1[m]=r;//将到来的读者放入等待队列中
noteArea.append("读者2到来,进入等待队列...\n");
break;
}
}
}
}elseif(str.equals("3")){//启动写者0,此处要启动一个对应的线程来处理对应的读者
[3].setIcon(im2);
Writew=newWrite(t,0,File,noteArea,jta[3]);
t[3]=newThread(w);
if(list2[0]==null&&Reader.getCount()==0){
t[3].start();
}else{
for(intm=0;mif(list2[m]==null){
list2[m]=w;//将到来的读者放入等待队列中
noteArea.append("写者0到来,进入等待队列...\n");
break;
}
}
}
}elseif(str.equals("4")){//启动读者0,此处要启动一个对应的线程来处理对应的读者
[4].setIcon(im2);
Writew=newWrite(t,1,File,noteArea,jta[4]);
t[4]=newThread(w);
if(Write.getMatu()==1&&Reader.getCount()==0){
t[4].start();