java实现读者写者问题(写着优先)
- 格式:doc
- 大小:63.50 KB
- 文档页数:15
2.读者—写者问题读者—写者问题(Readers-Writers problem)也是一个经典的并发程序设计问题,是经常出现的一种同步问题。
计算机系统中的数据(文件、记录)常被多个进程共享,但其中某些进程可能只要求读数据(称为读者Reader);另一些进程则要求修改数据(称为写者Writer)。
就共享数据而言,Reader和Writer是两组并发进程共享一组数据区,要求:(1)允许多个读者同时执行读操作;(2)不允许读者、写者同时操作;(3)不允许多个写者同时操作。
Reader和Writer的同步问题分为读者优先、弱写者优先(公平竞争)和强写者优先三种情况,它们的处理方式不同。
(1)读者优先。
对于读者优先,应满足下列条件:如果新读者到:①无读者、写者,新读者可以读;②有写者等待,但有其它读者正在读,则新读者也可以读;③有写者写,新读者等待。
如果新写者到:①无读者,新写者可以写;②有读者,新写者等待;③有其它写者,新写者等待。
单纯使用信号量不能解决读者与写者问题,必须引入计数器rc 对读进程计数;rc_mutex 是用于对计数器rc 操作的互斥信号量;write表示是否允许写的信号量;于是读者优先的程序设计如下:int rc=0; //用于记录当前的读者数量semaphore rc_mutex=1; //用于对共享变量rc 操作的互斥信号量semaphore write=1; //用于保证读者和写者互斥地访问的信号量void reader() /*读者进程*/do{P(rc_mutex); //开始对rc共享变量进行互斥访问rc ++; //来了一个读进程,读进程数加1if (rc==1) P(write);//如是第一个读进程,判断是否有写进程在临界区,//若有,读进程等待,若无,阻塞写进程V(rc_mutex); //结束对rc共享变量的互斥访问读文件;P(rc_mutex); //开始对rc共享变量的互斥访问r c--; //一个读进程读完,读进程数减1if (rc == 0) V(write);//最后一个离开临界区的读进程需要判断是否有写进程//需要进入临界区,若有,唤醒一个写进程进临界区V(rc_mutex); //结束对rc共享变量的互斥访问} while(1)void writer() /*写者进程*/do{P(write); //无读进程,进入写进程;若有读进程,写进程等待写文件;V(write); //写进程完成;判断是否有读进程需要进入临界区,//若有,唤醒一个读进程进临界区} while(1)读者优先的设计思想是读进程只要看到有其它读进程正在读,就可以继续进行读;写进程必须等待所有读进程都不读时才能写,即使写进程可能比一些读进程更早提出申请。
操作系统实验报告实验题目:ReaderWriter实验一.实验目的:1.通过编写和调试程序以加深对进程、线程管理方案的理解2.熟悉Windows多线程程序设计方法二.实验原理:读者-写者允许多个读者同时读一个数据对象,因为读文件不会使数据发生混乱,但不允许一个写者进程与其他读者进程或写者进程同时访问该数据对象。
文件是各个进程能互斥访问临界资源,读者进程和写者进程之间互斥。
在读者进程中,可以有多个读者读数据库,在读者进程的计数要互斥,避免发生错误,同时注意当第一个读者进程读时,一定要封锁写者进程。
当读者进程逐渐撤离时,要针对计数变量进行互斥操作,若当前为最后一个读者进程,读完后应唤醒写者进程。
所以应该分四类可能性:1.读者优先权比写者高,并且不用调配。
2.在一个读者已经占有文件的时候,全体读者的优先权才比写者高3.写者的优先权比读者的优先权高4.所有写者的和所有读者有相同的优先权三.实验代码:DataBaseBuffer:import java.awt.*;public class DataBaseBuffer extends Canvas{int[] readWantQ;int[] writerWantQ;String[] wantQ;int frameDelay = 1560;private int writerID;private int readerCount;private int wantCount;private int readerWantCount, writerWantCount;private int writerCount;private int wn, rn; // the number of readers and writersprivate int readTop, readBottom, writerTop, writerBottom;private int wantTop, wantBottom;private Font font;private FontMetrics fm;private boolean readLock = false;private boolean writeLock = false;public DataBaseBuffer( ){resize(500, 300);setBackground(Color.white);font = new Font("TimesRoman", Font.BOLD, 18);fm = getFontMetrics(font);}public void setSize(int readerN, int writerN){rn = readerN;wn = writerN;readTop = readBottom = writerTop = writerBottom = 0;readerCount = writerCount = readerWantCount = writerWantCount = 0;wantTop = wantBottom = 0;wantCount = 0;writerID = 0;readLock = false;writeLock = false;wantQ = new String[rn+wn];writerWantQ = new int[wn];readWantQ = new int[rn];repaint();}public synchronized void enterQueue(String s, int id){wantQ[wantTop] = s + id;wantTop ++;wantCount ++;repaint();}public synchronized void dequeue(String s, int id ){String str;str = s+id;while(!wantQ[0].equals(str)){try{ wait(); } catch(InterruptedException e) { } }for(int i = 0; i < (wantTop-1); i++){wantQ[i] = wantQ[i+1];}wantTop --;wantCount --;repaint();}public synchronized void changePosition(String s, int id) {String str;String tmp;int pos = 0; //to find the posting of 1st writer String wtr;wtr = s+id;while(!(wantQ[pos].equals(wtr))){pos++;}for(int i = 0; i < wantTop; i++){System.out.println(wantQ[i]);}str = wantQ[pos];for(int i = pos; i > 0; i--){wantQ[i] = wantQ[i-1];}wantQ[0] = str;repaint();for(int i = 0; i < wantTop; i++){System.out.println(wantQ[i]);}}public synchronized boolean hasWriterWant(){return (writerWantCount > 0);}public synchronized boolean hasReaderWant(){return (readerWantCount > 0);}public synchronized void acquireReadLock(ReaderWriterApplet applet, int id){readWantQ[readTop] = id; //nums is the index for readWantQreadTop = (readTop+1) % rn;readerWantCount ++;repaint();notifyAll();enterQueue("R", id);applet.r[id].status = 1; //want inapplet.mc.println(applet.r[id].status, "r", id);try{ applet.r[id].sleep(frameDelay);}catch(InterruptedException e) {}if(applet.writerPriority){while(hasWriterWant() || writeLock){applet.r[id].status = 3;applet.mc.println(applet.r[id].status, "r", id);try{ wait(); } catch(InterruptedException e) { } }//end of while loop}//end of if statementelse if(applet.readerPriority){while(readWantQ[readBottom] != id){try { wait(); } catch(InterruptedException e) {} }changePosition("R",id);}else{applet.r[id].status = 3;applet.mc.println(applet.r[id].status, "r", id);while(!wantQ[wantBottom].equals("R"+id)){try{ wait(); } catch(InterruptedException e) { } }}while(writeLock) //if there is any writer is writing {applet.r[id].status = 3;applet.mc.println(applet.r[id].status, "r", id);try{ wait(); } catch(InterruptedException e) { } }if(readLock == false){readLock = true;notifyAll();}readBottom = (readBottom+1) %rn;readerWantCount --;dequeue("R", id);readerCount ++;repaint();applet.r[id].status = 2;applet.mc.println(applet.r[id].status, "r", id);System.out.println("Reader "+id + "is reading");notifyAll();}public synchronized boolean hasReader(){return (readerCount > 0);}public synchronized void releaseReadLock(ReaderWriterApplet applet,int id){readerCount --;notifyAll();if(!hasReader()){readLock = false;notifyAll();applet.r[id].status = 4;applet.mc.println(applet.r[id].status, "r", id);}repaint();}public synchronized void acquireWriteLock(ReaderWriterApplet applet, int id){writerWantQ[writerTop] = id;writerTop=(writerTop+1)%wn;writerWantCount ++;notifyAll();repaint();enterQueue("W", id);applet.w[id].status = 1; //want inapplet.mc.println(applet.w[id].status, "w", id);try{ applet.w[id].sleep(frameDelay); }catch(InterruptedException e) {}if(applet.writerPriority){while(writerWantQ[writerBottom] != id){try{ wait(); } catch(InterruptedException e) { }}changePosition("W", id);while(readLock || writeLock){try{ wait(); } catch(InterruptedException e) { }}}else if(applet.readerPriority){while(!(wantQ[wantBottom].equals("W"+id)) || hasReaderWant() || readLock || writeLock){try{ wait(); } catch(InterruptedException e) { }}System.out.println("Writer "+ id + " move forward");}else{while(!(wantQ[wantBottom].equals("W"+id))){try{ wait(); } catch(InterruptedException e) { }}while(readLock || writeLock){try{ wait(); } catch(InterruptedException e) { }}}writeLock = true;System.out.println("Writer "+ id+ " Got the lock ******");notifyAll();dequeue("W", id);writerBottom = (writerBottom + 1)%wn;writerID = id;writerWantCount --;writerCount++;notifyAll();repaint();applet.w[id].status = 2;applet.mc.println(applet.w[id].status, "w", id);}public synchronized void releaseWriteLock(ReaderWriterApplet applet, int id){System.out.println("Writer " + id + " released the lock");writerCount --;writerID = 0;writeLock = false;notifyAll();repaint();}public void clear(){writerBottom = writerTop = 0;readBottom = readTop = 0;writerWantCount = 0;readerWantCount = 0;readerCount = 0;writerCount = 0;readLock = writeLock = false;writerWantQ = new int[wn];readWantQ = new int[rn];wantQ = new String[wn+rn];wantTop = wantBottom = 0;}public void paint(Graphics g){int xpos = 630;int ypos = 5;g.setFont(new Font("TimesRoman", Font.BOLD, 11));g.setColor(Color.green);g.draw3DRect(xpos, ypos, 10, 10, true);g.fillRect(xpos, ypos, 10, 10);g.drawString("Reading", xpos+15, ypos+10);g.setColor(Color.red);g.draw3DRect(xpos, ypos+14, 10, 10, true);g.fillRect(xpos, ypos+14, 10, 10);g.drawString("Writing", xpos+15, ypos+25);g.setColor(Color.blue);g.draw3DRect(xpos, ypos+28, 10, 10, true);g.fillRect(xpos, ypos+28, 10, 10);g.drawString("Empty", xpos+15, ypos+40);g.setFont(new Font("TimesRoman", Font.BOLD, 14));g.setColor(Color.blue);xpos = 40;ypos = 50;g.drawString("Waiting Queue", xpos-5, ypos-20);int i = wantBottom;for(int j = 0; j < wantCount; j++){if( wantQ[i].equals("W1") || wantQ[i].equals("W2")||wantQ[i].equals("W3")|| wantQ[i].equals("W4")||wantQ[i].equals("W5")){g.setColor(Color.red);g.drawString(wantQ[i], xpos+450-30*j, ypos-18);g.draw3DRect(xpos+445-30*j, ypos-35, 28, 28, true);}if( wantQ[i].equals("R1") || wantQ[i].equals("R2")||wantQ[i].equals("R3")|| wantQ[i].equals("R4")||wantQ[i].equals("R5")){g.setColor(Color.green);g.drawString(wantQ[i], xpos+450-30*j, ypos-18);g.draw3DRect(xpos+445-30*j, ypos-35, 28, 28, true);}i = (i+1) % (wn+rn);}if(readLock) g.setColor(Color.green);else if(writeLock) g.setColor(Color.red);else g.setColor(Color.blue);g.draw3DRect(xpos+250, ypos+20, 100, 100, true);g.fillRect(xpos+250, ypos+20, 100, 100);if(readLock){g.setColor(Color.black);g.drawString("Reading", xpos + 270, ypos+60);}else if(writeLock){g.setColor(Color.black);g.drawString("W " +Integer.toString(writerID), xpos + 280,ypos+45);g.drawString("Writing", xpos + 270, ypos+60);}}}MessageCanvas:import java.awt.*;class MessageCanvas extends Canvas{private Font font;private FontMetrics fm;private int[] writerStatus;private int[] readerStatus;private int msgHeight;private int msgWidth;private int pn, cn;private int frameDelay = 256;public MessageCanvas( ){resize(size().width, 50);setBackground(Color.green);font = new Font("TimesRoman", 1, 18);fm = getFontMetrics(font);msgHeight = fm.getHeight();}public void setMessage(int writerN, int readerN) {pn = writerN;cn = readerN;writerStatus = new int[pn+1];readerStatus = new int[cn+1];repaint();}void println(String s){msgWidth = fm.stringWidth(s);repaint();}void println(int s, String st, int id){if(st.equals("w"))writerStatus[id] = s;elsereaderStatus[id] = s;repaint();}void println(int s, int number, String st, int id){if(st.equals("w")){writerStatus[id] = s;}else{readerStatus[id] = s;}repaint();}public void paint(Graphics g){g.setFont(font);int xpos = 60;int ypos = 40;g.drawString("Status of Readers: ", 60, 20);g.drawString("Status of Writers: ", 360, 20);g.setFont(new Font("TimesRoman", 1, 14));for(int i=1; i<=cn;i++){g.setColor(Color.black);g.drawString("R" + i, xpos, ypos+(15*i+10*(i-1)));if(readerStatus[i] == 0){g.setColor(Color.yellow);g.fillOval(xpos+60, ypos+(2*i+22*(i-1)), 18, 18);g.drawString("Sleeping ...", xpos+120, ypos+(15*i + 10*(i-1)));}else if (readerStatus[i] == 1){g.setColor(Color.gray);g.fillOval(xpos+60, ypos+(2*i+22*(i-1)), 18, 18);g.drawString("Want to read", xpos+120, ypos+(15*i + 10*(i-1)));}else if (readerStatus[i] == 3){g.setColor(Color.gray);g.fillOval(xpos+60, ypos+(2*i+22*(i-1)), 18, 18);g.drawString("Waiting in the queue", xpos+120, ypos+(15*i + 10*(i-1)));}else if (readerStatus[i] == 2){g.setColor(Color.blue);g.fillOval(xpos+60, ypos+(2*i+22*(i-1)), 18, 18);g.drawString("Reading...", xpos+120, ypos+(15*i + 10*(i-1)));}}xpos = 360;ypos = 40;for(int i=1; i<=pn; i++){g.setColor(Color.black);g.drawString("W" + i, xpos, ypos+(15*i+10*(i-1)));if(writerStatus[i] == 0){g.setColor(Color.yellow);g.fillOval(xpos+60, ypos+(2*i+22*(i-1)), 18, 18);g.drawString("Sleeping ...", xpos+120, ypos+(15*i + 10*(i-1)));}else if (writerStatus[i] == 1){g.setColor(Color.gray);g.fillOval(xpos+60, ypos+(2*i+22*(i-1)), 18, 18);g.drawString("Waiting in the queue", xpos+120, ypos+(15*i + 10*(i-1)));}else if (writerStatus[i] == 2){g.setColor(Color.blue);g.fillOval(xpos+60, ypos+(2*i+22*(i-1)), 18, 18);g.drawString("Writing ...", xpos+120, ypos+(15*i + 10*(i-1)));}}}}Reader:public class Reader extends Thread{private DataBaseBuffer buffer;private ReaderWriterApplet tapplet;private int cid;int delay = 6500;int status = 0;public Reader(ReaderWriterApplet applet, DataBaseBuffer db, int id){ buffer = db;tapplet = applet;cid = id;}public void run(){while(true){try{status = 0;tapplet.mc.println(status, "r", cid);sleep((int) (Math.random()*delay));buffer.acquireReadLock(tapplet, cid);sleep((int) (Math.random()*delay));buffer.releaseReadLock(tapplet, cid);} catch(InterruptedException e){System.err.println("Reader Execption " + e.toString());}}}}ReaderWriterApplet:import java.awt.*;import java.awt.event.*;import java.util.*;import java.applet.Applet;import ng.*;public class ReaderWriterApplet extends Applet{private ReaderWriterApplet applet = this;private DataBaseBuffer myBuffer;private int buffersize;private Button fastButton, slowButton, stopButton, startButton, pauseButton, continueButton;private Button stopReaderButton, stopWriterButton;private Panel buttonPanel, priorityPanel, namePanel;private Choice priority, reader, writer;private Thread at;private int readerN = 1;private int writerN = 1;boolean readerPriority = false;boolean writerPriority = false;boolean samePriority = true; //default priority of readers and writers MessageCanvas mc;Reader[] r;Writer[] w;synchronized void startPushed() {notify();}synchronized void stopPushed() {notify();}public void init() {myBuffer = new DataBaseBuffer();mc = new MessageCanvas();resize(800, 600);setLayout(new GridLayout(3, 1));add(myBuffer);add(mc);buttonPanel = new Panel();priorityPanel = new Panel();namePanel = new Panel();Panel bPanel = new Panel(); // to hold all buttons and the labels bPanel.setFont(new Font("TimesRoman", Font.BOLD, 14));bPanel.setLayout(new GridLayout(3, 1));buttonPanel.add(startButton = new Button("START"));buttonPanel.add(stopButton = new Button("STOP"));buttonPanel.add(pauseButton = new Button("PAUSE"));buttonPanel.add(continueButton = new Button("CONTINUE"));buttonPanel.add(fastButton = new Button("FASTER"));buttonPanel.add(slowButton = new Button("SLOWER"));Panel choicePanel = new Panel(); //to hold all the choice boxespriority = new Choice();priority.addItem("Same Priority");priority.addItem("Writers Have Priority");priority.addItem("Readers Have Priority");priority.select("Same Priority");Label priorityLabel = new Label("Priority", 2);priorityLabel.setBackground(Color.lightGray);priorityPanel.add(priorityLabel);priorityPanel.add(priority);choicePanel.add(priorityPanel);reader = new Choice();for(int i = 0; i <=5; i++){reader.addItem(Integer.toString(i));}reader.select("1");Label readerLabel = new Label("Number of Readers", 2);readerLabel.setBackground(Color.lightGray);Panel readerPanel = new Panel();readerPanel.add(readerLabel);readerPanel.add(reader);writer = new Choice();for(int i = 0; i<=5; i++){writer.addItem(Integer.toString(i));}writer.select("1");Label writerLabel = new Label("Number of Writers", 2);writerLabel.setBackground(Color.lightGray);Panel writerPanel = new Panel();writerPanel.add(writerLabel);writerPanel.add(writer);Label nameLabel = new Label("Readers/Writers Animation");nameLabel.setFont(new Font("TimesRoman", Font.BOLD, 18));nameLabel.setForeground(Color.blue);namePanel.add(nameLabel);choicePanel.add(readerPanel);choicePanel.add(writerPanel);bPanel.add(choicePanel);bPanel.add(buttonPanel);bPanel.add(namePanel);add(bPanel);}public boolean action(Event evt, Object arg){if(evt.target == priority){if(arg.equals("Writers Have Priority")){writerPriority = true;readerPriority = false;samePriority = false;}else if(arg.equals("Readers Have Priority")) {readerPriority = true;writerPriority = false;samePriority = false;}else{readerPriority = false;writerPriority = false;samePriority = false;}return true;}else if(evt.target == reader){readerN = Integer.parseInt(arg.toString());return true;}else if(evt.target == writer){writerN = Integer.parseInt(arg.toString());return true;}else if(arg.equals("FASTER")){int newDelay;if(readerN != 0) newDelay = r[1].delay;else newDelay = w[1].delay;newDelay /= 2;newDelay = newDelay < 100 ? 100: newDelay;for(int i = 1; i <= readerN; i++){r[i].delay = newDelay;for(int i = 1; i <= writerN; i++){w[i].delay = newDelay;}return true;}else if(arg.equals("SLOWER")){int newDelay;if(readerN !=0) newDelay = w[1].delay;else newDelay = r[1].delay;newDelay *= 2;for(int i = 1; i <= readerN; i++){r[i].delay = newDelay;}for(int i = 1; i <= writerN; i++){w[i].delay = newDelay;}return true;}else if(arg.equals("PAUSE")){for(int i = 1; i <= readerN; i++){r[i].suspend();}for(int i = 1; i <= writerN; i++){w[i].suspend();}fastButton.setEnabled(false);slowButton.setEnabled(false);return true;}else if(arg.equals("CONTINUE")){for(int i = 1; i <= readerN; i++){if(r[i].isAlive()) r[i].resume();}for(int i = 1; i <= writerN; i++)if(w[i].isAlive()) w[i].resume();}fastButton.setEnabled(true);slowButton.setEnabled(true);return true;}else if(arg.equals("START")){r = new Reader[readerN+1]; //Reader[0] is a dummy slotw = new Writer[writerN+1];System.out.println("readers: "+readerN+" writers: " + writerN);mc.setMessage(writerN, readerN);myBuffer.setSize(readerN, writerN);for(int i = 1; i <= readerN; i++){r[i] = new Reader(applet, myBuffer, i);}for(int i = 1; i <= writerN; i++){w[i] = new Writer(applet, myBuffer, i);}for(int i = 1; i <= writerN; i++){w[i].start();}for(int i = 1; i <= readerN; i++){r[i].start();}fastButton.setEnabled(true);slowButton.setEnabled(true);startButton.setEnabled(false);reader.setEnabled(false);writer.setEnabled(false);priority.setEnabled(false);applet.startPushed();return true;}else if(arg.equals("STOP")){for(int i = 1; i <= readerN; i++){if(r[i].isAlive())r[i].stop();r[i] = null;}for(int i = 1; i <= writerN; i++){if(w[i].isAlive())w[i].stop();w[i] = null;}applet.stopPushed();startButton.setEnabled(true);fastButton.setEnabled(true);slowButton.setEnabled(true);reader.setEnabled(true);writer.setEnabled(true);priority.setEnabled(true);if(at != null) at.stop();at = null;return true;}else{ return false;}}}Writer:public class Writer extends Thread{private DataBaseBuffer buffer;private ReaderWriterApplet tapplet;private int id;int delay = 6500;int status = 0;public Writer(ReaderWriterApplet applet, DataBaseBuffer db, int id){ buffer = db;tapplet = applet;this.id = id;}public void run(){while(true){try{status = 0;tapplet.mc.println(status, "w", id);sleep((int)(Math.random()*delay));buffer.acquireWriteLock(tapplet, id);sleep((int) (Math.random()*delay));buffer.releaseWriteLock(tapplet, id);} catch(InterruptedException e){System.err.println("Execption " + e.toString());}}}}四.实验结果:运行如下:。
目录摘要 (1)1.设计思想 (2)2.各模块的伪码算法 (3)3. 函数关系调用图 (5)4.程序测试结果 (6)设计总结 (9)参考文献 (10)致谢 (11)摘要本设计的读者写者问题,是指一些进程共享一个数据区。
数据区可以使一个文件、一块内存空间或者一组寄存器。
Reader进程只能读数据区中的数据,而writer进程必须与其他进程互斥地访问共享对象的同步问题。
读者写者问题可以这样的描述, 有一群写者和一群读者, 写者在写同一本书, 读者也在读这本书, 多个读者可以同时读这本书。
但是,只能有一个写者在写书, 并且,读者必写者优先,也就是说,读者和写者同时提出请求时,读者优先。
当读者提出请求时需要有一个互斥操作, 另外, 需要有一个信号量S来确定当前是否可操作。
本设计方案就是通过利用记录型信号量对读者写者问题的解决过程进行模拟演示,形象地阐述记录型信号量机制的工作原理。
关键词:共享对象,互斥,同步,信号量1.设计思想本设计借助C语言实现进程同步和互斥的经典问题--读者写者问题,用高级语言编写和调试一个进程同步程序,以加深对进程同步机制的理解。
通过用C 语言模拟进程同步实现,加深理解有关进程同步和互斥机制的概念及P、V操作的应用。
学生通过该题目的设计过程,掌握读者、写者问题的原理、软件开发方法并提高解决实际问题的能力。
在 Windows环境下,创建一个包含n个线程的控制台进程。
用这n个线每个线程按相应测试数据文件的要求,进行读写操作。
程来表示 n 个读者或写者。
请用信号量机制分别实现读者优先和写者优先的读者-写者问题。
将所有的读者和所有的写者分别放进两个等待队列中,当读允许时就让读者队列释放一个或多个读者,当写允许时,释放第一个写者操作。
读者-写者的读写限制(包括读者优先和写者优先)1)写-写互斥,即不能有两个写者同时进行写操作;2)读-写互斥,即不能同时有一个读者在读,同时却有一个写者在写;3)读读允许,即可以有 2 个以上的读者同时读;4)读者优先附加条件:如果一个读者申请进行读操作,同时又有一个读操作正在进行读操作,则该读者可以直接开始读操作;5)写者优先附加条件:如果一个读者申请进行读操作时已经有一个写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。
采用“写优先”策略的“读者-写者”问题学院计算机科学与技术专业计算机科学与技术学号学生姓名指导教师姓名2014-3-11目录一、设计目的与内容 ................................................ 错误!未定义书签。
(1 )、课程设计的目的 (1)(2 ) 、课程设计的内容 (1)(3 ) 、课程设计的要求 (1)二、算法的基本思想 ................................................ 错误!未定义书签。
三、模块流程图......................................................... 错误!未定义书签。
四、测试结果............................................................. 错误!未定义书签。
五、结论..................................................................... 错误!未定义书签。
六、源程序................................................................. 错误!未定义书签。
一、设计目的与内容(1)课程设计的目的:操作系统课程设计是计算机专业重要的教学环节,它为学生提供了一个既动手又动脑,将课本上的理论知识和实际有机的结合起来,独立分析和解决问题的机会。
●进一步巩固和复习操作系统的基础知识。
●培养学生结构化程序、模块化程序设计的方法和能力。
●提高学生调试程序的技巧和软件设计的能力。
●提高学生分析问题、解决问题以及综合利用C语言进行程序设计的能力。
(2) 课程设计的内容:用高级语言编写和调试一个采用“写优先”策略的“读者—写者”问题的模拟程序。
(3) 课程设计的要求:1.读者与写者至少包括ID、进入内存时间、读写时间三项内容,可在界面上进行输入。
读者写者问题写者优先参考答案HUA system office room 【HUA16H-TTMS2A-HUAS8Q8-HUAH1688】【写者优先】在读者、写者问题中,如果总有读者进程进行读操作,会造成写者进程永远都不能进行写操作(读者优先),即所谓的写者饿死现象。
给出读者、写者问题的另一个解决方案:即保证当有一个写者进程想写时,不允许读者进程再进入,直到写者写完为止,即写者优先。
让我们先回顾读者写者问题[1]:一个数据对象若被多个并发进程所共享,且其中一些进程只要求读该数据对象的内容,而另一些进程则要求写操作,对此,我们把只想读的进程称为“读者”,而把要求写的进程称为“写者”。
在读者、写者问题中,任何时刻要求“写者”最多只允许有一个执行,而“读者”则允许有多个同时执行。
因为多个“读者”的行为互不干扰,他们只是读数据,而不会改变数据对象的内容,而“写者”则不同,他们要改变数据对象的内容,如果他们同时操作,则数据对象的内容将会变得不可知。
所以对共享资源的读写操作的限制条件是:允许任意多的读进程同时读;一次只允许一个写进程进行写操作;如果有一个写进程正在进行写操作,禁止任何读进程进行读操作。
为了解决该问题,我们只需解决“写者与写者”和“写者与第一个读者”的互斥问题即可,为此我们引入一个互斥信号量Wmutex,为了记录谁是第一个读者,我们用一个共享整型变量Rcount 作一个计数器。
而在解决问题的过程中,由于我们使用了共享变量Rcount,该变量又是一个临界资源,对于它的访问仍需要互斥进行,所以需要一个互斥信号量Rmutex,算法如下:}}现在回到【写者优先】优先问题【写者优先】在读者、写者问题中,如果总有读者进程进行读操作,会造成写者进程永远都不能进行写操作(读者优先),即所谓的写者饿死现象。
给出读者、写者问题的另一个解决方案:即保证当有一个写者进程想写时,不允许读者进程再进入,直到写者写完为止,即写者优先。
实验一实验报告学号:20092128 姓名:徐卓远实验序号:1实验名称:用信号量来实现读者-写者问题实验目的:理解进程同步与互斥的概念,掌握用信号量来实现进程的同步与互斥。
实验设计及实现:为了实现读者和写者的读写过程,将每个读者和每个写者作为了一个单独的线程,所以设置了两个类,一个是读者类Reader,一个是写者类Writer.以读者类为例:一个读者的动作过程为由睡眠->等待->开始读->结束读->睡眠的一个循环过程,而一个写者的动作过程也为此.读者调用方法napping()进行等待,调用startRead()方法开始读,最后在调用endReading()方法结束读入,释放运行空间.写者同读者.但是为了实现读者写者之间的写-写互斥,读-写互斥,读-读允许,需要另外一个类Database,类中分别用关于读者的方法和写者的方法来控制读写之间的这种关系.首先要实现睡眠的方法napping(),读者和写者在睡眠过程都应该是一样的,只是他们睡眠的时间不同,所以只需写出一个方法:public static void napping() {int sleepTime = (int) (NAP_TIME * Math.random()); try {Thread.sleep(sleepTime * 1000);} catch (Exception e) {e.printStackTrace();}}在方法中,控制线程休眠随机的时间,由于每个读者或写者都是一个线程,而每个读者或写者他们工作休眠的时间都不一定相同,他们请求工作的时间也不一定相同,所以取了随机时间其次设置了读者的两个方法,开始读和结束读,由于这只是个模拟读写问题,所以只需要知道结果就行,就不用显示出他是怎么读的.在开始读中,当有写者在写时,读者需要等待wait(),在没有人在工作时,如果有写者和读者同时请求,那么就让写者先进,这是写者优先.所以这就归纳于一种情况, 当读者布尔变量dbReading为FALSE时,如果有需要工作的写者,那么读者就等待.当读者请求读入后,计数有多少读者需要工作的变量readerCount +1,如果这是第一个进入工作的读者就需要将显示是否有读者在工作的读者布尔变量变为TRUE.public synchronized int startRead() {if (dbReading == false) {while (writerCount > 0) {try {System.out.println("reader is waiting");wait();} catch (Exception e) {System.out.println(e.toString());e.printStackTrace();}}}++readerCount;if (readerCount == 1) {dbReading = true;}return readerCount;}读结束时,计数需要读的读者数-1,然后释放出空间给需要工作的人.public synchronized int endReading() {--readerCount;if (readerCount == 0) {dbReading = false;}notifyAll();//释放出空间System.out.println("one reader is done, reading.Count=" + readerCount);return readerCount;}第三,编写关于写者的开始写和结束写方法,在开始写方法中,首先要将计数需要写的变量writerCount+1,写者如果有读者或者有写者正在工作,那么就等待,如果没有就直接进入写,然后表示是否有写者在写的布尔变量dbWriting变为TRUEpublic synchronized void startWriting() {//控制写者开始进入写++writerCount;while (dbReading == true || dbWriting == true) {try {System.out.println("Writer is waiting");wait();} catch (Exception e) {System.out.println(e.toString());}}dbWriting = true;}结束时只需将writerCount-1和dbWriting为FALSE,然后释放出空间.public synchronized void endWriting() {//控制写者结束写入--writerCount;dbWriting = false;System.out.println("one writer is done, writing.Count=" + writerCount);notifyAll();}源代码及程序流程图主类:package rw;/**** @author xzy*/public class Main {public static void main(String[] args) {Database db=new Database();//实例化类Database为dbReader r1=new Reader(1,db);//实例化类Reader为r1Reader r2=new Reader(2,db);Reader r3=new Reader(3,db);Reader r4=new Reader(4,db);Writer w1=new Writer(1,db);//实例化类Writer为w1Writer w2=new Writer(2,db);r1.start();//读者1调用start()方法开始进入读写这个模拟环境中r2.start();r3.start();w1.start();r4.start();w2.start();}}Database类:package rw;/**** @author xzy*/public class Database {private static final int NAP_TIME = 5;private int readerCount;//变量计数需要读的读者private int writerCount;//变量计数需要写的写者private boolean dbReading;//表示是否有读者在读private boolean dbWriting;//表示是否有写者在写public Database() {readerCount = 0;//变量计数需要读的读者为0writerCount = 0;//变量计数需要写的写者为0dbReading = false;//表示没有读者正在读入dbWriting = false;//表示没有写者正在写入}public static void napping() {//控制睡眠的时间int sleepTime = (int) (NAP_TIME * Math.random());//睡眠时间随机try {Thread.sleep(sleepTime * 1000);} catch (Exception e) {e.printStackTrace();}}public synchronized int startRead() {//控制读者开始读if (dbReading == false) {//当没有读者在读时while (writerCount > 0) {//当有写者想写时try {System.out.println("reader is waiting");wait();//等待} catch (Exception e) {System.out.println(e.toString());e.printStackTrace();}}}++readerCount;//请求读入的读者数加一if (readerCount == 1) {dbReading = true;//标明有读者正在读}return readerCount;}public synchronized int endReading() {//控制读者结束读入--readerCount;if (readerCount == 0) {dbReading = false;}notifyAll();//释放出空间给其他的线程System.out.println("one reader is done, reading. Count=" + readerCount);return readerCount;}public synchronized void startWriting() {//控制写者开始进入写++writerCount;//想写的写者数加一while (dbReading == true || dbWriting == true) {//当有读者在读或者有写者在写时都得等待try {System.out.println("Writer is waiting");wait();} catch (Exception e) {System.out.println(e.toString());}}dbWriting = true;}public synchronized void endWriting() {//控制写者结束写入--writerCount;dbWriting = false;System.out.println("one writer is done, writing. Count=" + writerCount);notifyAll();}}Reader类:package rw;/**** @author xzy*/public class Reader extends Thread {private Database server;//设置一个Database变量用来控制该读者private int readerNum;//设置该读者的标志public Reader(int r, Database db) {readerNum = r;server = db;}@Overridepublic void run() {int c;while (true) {System.out.println("reader " + readerNum + " is sleeping");Database.napping();//表明读者正在睡眠状态System.out.println("reader " + readerNum + " wants to read");c = server.startRead();//读者开始请求读入工作System.out.println("reader " + readerNum + " is reading. Count=" + c);Database.napping();//读者处于工作阶段c = server.endReading();//读者结束工作System.out.println("It is reader " + readerNum + " who has done reading according to count=" + c);}}}Writer类:package rw;/**** @author xzy*/public class Writer extends Thread {private Database server;//设置一个Database变量用来控制该写者private int writerNum;//设置该写者的标志public Writer(int w, Database db) {writerNum = w;server = db;@Overridepublic void run() {while (true) {System.out.println("Writer " + writerNum + " is sleeping");Database.napping();//表明写者正在睡眠状态System.out.println("Writer " + writerNum + " wants to write");server.startWriting();//写者开始请求读入工作System.out.println("Writer " + writerNum + " is writing");Database.napping();//写者处于工作阶段server.endWriting();//写者结束工作System.out.println("It is Writer " + writerNum + " who has done writing .");}}}写者:实验当堂所要完成的事情:解决编译和运行出现的问题.编译过程中出现的问题及其相应解决:1.一个读者或者写者工作完时无法释放出空间给其他人解决:用了notifyall()方法,最开始只知道notify()方法,要释放出空间给所有人平等使用权利那么就必须用notifyall()方法.运行过程中出现的问题及其相应解决:1.实现了写者优先但是没有实现读读允许解决:加了一个判断if,如果没有读者读才做出写者优先的判断.实验总结通过本次实验,我对读者-写者的过程有了清楚的认识,对互斥和同步有了更深一步的了解,在最开始的实验中,我没有正确理解好写者优先,当有写者等待时,读者就不能进入了,这样就没有实现读读允许,意识到了后,加了个if判断解决了这一问题.在JA V A的线程的使用方法中,释放空间这个方法过去一直用的是notify(),但是由于一直是对单一的线程,这次实验中发现这个方法在这里不可行,所以即时查阅了资料用了notifyall()方法,总的来说,这次是操作系统的第一次实验,感觉最主要的是把脉络理清楚,写代码的工作要比理清脉络简单.。
读者-写者问题有同学反映“读者-写者问题”的代码比较难理解。
主要是因为Windows提供了一种互斥机制称为“Critical Section”,中文翻译为“临界区”,这个名字具有迷惑性,因为,它容易与我们课本上讲的“临界区”的概念混淆。
课本上临界区指“对临界资源进行访问的代码”;而这种称为“Critical Section”互斥机制,并不是这个意思,而是访问临界区之前的一种加锁机制,与Mutex 信号量的作用类似,只是“Critical Section”互斥机制只能在同一进程内部各个线程间使用,而Mutex互斥机制是可以跨进程使用的。
为帮助大家更容易理解读者-写者的代码,下面的代码用Mutex互斥机制替换了“Critical Section”互斥机制,并添加了部分注释,并用蓝色标注,其原理都是一样的。
#include "windows.h"#include "process.h"#include <conio.h>#include <stdlib.h>#include <fstream.h>#include <io.h>#include <string.h>#include <stdio.h>#define READER 'R' // 读者#define WRITER 'W' // 写者#define INTE_PER_SEC 1000 // 每秒时钟中断数目#define MAX_THREAD_NUM 64 // 最大线程数目#define MAX_FILE_NUM 32 // 最大数据文件数目#define MAX_STR_LEN 32 // 字符串长度volatile int readcount = 0; // 读者数目HANDLE RP_Write;struct ThreadInfo // 定义线程数据结构{int serial; // 线程序号char entity; // 线程类别(判断是读者线程还是写者线程)double delay; // 线程延迟double persist; // 线程读写操作持续时间};/////////////////////////////////////////////////////////////////////////// 读者优先——读者线程/// p:读者线程信息unsigned int __stdcall RP_ReaderThread(void *p){// 互斥变量HANDLE h_Mutex;h_Mutex = OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex_for_readcount");DWORD wait_for_mutex; //等待互斥变量所有权DWORD m_delay; //延迟时间DWORD m_persist; //读文件持续时间int m_serial; //线程序号//从参数中获得信息m_serial = ((ThreadInfo *)(p))->serial;m_delay = (DWORD)(((ThreadInfo *)(p))->delay*INTE_PER_SEC);m_persist = (DWORD)(((ThreadInfo*)(p))->persist*INTE_PER_SEC);Sleep (m_delay) ; //延迟等待printf("Reader thread %d sents the reading require......\n",m_serial);//等待互斥信号,保证对readcount的访问、修改互斥wait_for_mutex = WaitForSingleObject(h_Mutex,-1);// 读者数目增加readcount++;if(readcount ==1){//这是第一个读者,第二个读者到来时,readcount为2,if的条件不满足,不会进入if语句内部执行//这是第一个读者,如果此刻没有写者正在写,则RP_Write信号量状态为可用(未占用),那它就必须先占用(锁定)RP_Write信号量,这就实现了读-写互斥//如果此刻有写者正在写,则RP_Write信号量被写者占用(锁定),读者想对RP_Write加锁就会阻塞在此,等待RP_Write信号量释放后,才能继续运行WaitForSingleObject(RP_Write, INFINITE);}ReleaseMutex(h_Mutex) ; //释放互斥信号// 读文件printf("Reader thread %d begins to read file.\n",m_serial);Sleep(m_persist) ;// 退出线程printf("Reader thread %d finished reading file.\n",m_serial);//等待互斥信号,保证对readcount的访问、修改互斥wait_for_mutex = WaitForSingleObject(h_Mutex,-1) ;//读者数目减少readcount-- ;if(readcount == 0){//如果所有读者读完,则释放RP_Write信号量;此刻若有写者正在等待(处于阻塞状态),将(自动)唤醒写者ReleaseMutex(RP_Write);}ReleaseMutex(h_Mutex) ; //释放互斥信号return 0;}////////////////////////////////////////////////////////////////////////// 读者优先——写者线程// p:写者线程信息unsigned int __stdcall RP_WriterThread(void* p){DWORD m_delay; //延迟时间DWORD m_persist; //写文件持续时间int m_serial; //线程序号//从参数中获得信息m_serial = ((ThreadInfo *)(p))->serial;m_delay = (DWORD)(((ThreadInfo *)(p))->delay*INTE_PER_SEC) ;m_persist = (DWORD)(((ThreadInfo *)(p))->persist*INTE_PER_SEC) ;Sleep (m_delay); //延迟等待printf("Writer thread %d sents the writing require.\n",m_serial);// 写者在进行写数据之前,必须确定没有其它写者正在写,也没有其它读者在读,// 通过RP_Write互斥量实现,若有其它写者正在写或其它读者在读,则该写者调用“WaitForSingleObject(RP_Write, INFINITE);”后将阻塞在此// 等待RP_Write信号量释放后,才能够继续向下执行。
linux多线程编程——读者优先、写者优先问题读者优先描述如果读者来:1) ⽆读者、写着,新读者可以读;2) ⽆写者等待,但有其他读者正在读,新读者可以读;3) 有写者等待,但有其他读者正在读,新读者可以读;4) 有写者写,新读者等如果写者来:1) ⽆读者,新写者可以写;2) 有读者,新写者等待;3) 有其他写者写或等待,新写者等待写者优先描述如果读者来:1) ⽆读者、写者,新读者可以读;2) ⽆写者等待,但有其他读者正在读,新读者可以读;3) 有写者等待,但有其他读者正在读,新读者等;4) 有写者写,新读者等如果写者来:1) ⽆读者,新写者可以写;2) 有读者,新写者等待;3) 有其他写者或等待,新写者等待信号量和互斥锁的区别l 互斥量⽤于线程的互斥,信号量⽤于线程的同步。
这是互斥量和信号量的根本区别,也就是互斥和同步之间的区别。
互斥:是指某⼀资源同时只允许⼀个访问者对其进⾏访问,具有唯⼀性和排它性。
但互斥⽆法限制访问者对资源的访问顺序,即访问是⽆序的。
同步:是指在互斥的基础上(⼤多数情况),通过其它机制实现访问者对资源的有序访问。
在⼤多数情况下,同步已经实现了互斥,特别是所有写⼊资源的情况必定是互斥的。
少数情况是指可以允许多个访问者同时访问资源l 互斥量值只能为0/1,信号量值可以为⾮负整数。
也就是说,⼀个互斥量只能⽤于⼀个资源的互斥访问,它不能实现多个资源的多线程互斥问题。
信号量可以实现多个同类资源的多线程互斥和同步。
当信号量为单值信号量是,也可以完成⼀个资源的互斥访问。
l 互斥量的加锁和解锁必须由同⼀线程分别对应使⽤,信号量可以由⼀个线程释放,另⼀个线程得到。
读者优先使⽤互斥锁来确保同⼀时间只能⼀个进程写⽂件,实现互斥。
使⽤信号量来实现访问资源的同步。
⾸先,写者的代码应该是这样⼀种形式,才能保证同⼀时刻只有⼀个写者修改数据。
考虑到写者对读者的影响是:当任何读者想读时,写者都必须被阻塞;并且,读者阻塞了写者并停⽌阻塞之前,后续的任何写者都会读者优先于执⾏。
OS:读者写者问题(写者优先+LINUX+多线程+互斥量+代码)⼀. 引⼦最近想⾃⼰写个简单的 WEB SERVER ,为了先练练⼿,熟悉下在LINUX系统使⽤基本的进程、线程、互斥等,就拿以前学过的 OS 问题开开⼑啦。
记得当年学读者写者问题,尤其是写者优先的时候,那是真⼼纠结啊。
刚才还觉得理解了,过⼀会⼉⼜糊涂了。
现在重新再看,还是容易纠结。
没办法,⽤得少。
我把读者优先和写者优先都实现了⼀下。
选择性重看了⼩部分《unix⾼程》使⽤了多线程+互斥量实现。
⼆. 互斥量与信号量互斥量如其名,同⼀时间只能被⼀个线程占有,实现线程间对某种数据结构的互斥访问。
试图对⼀个已经加锁的互斥量加锁,会导致线程阻塞。
允许多个线程对同⼀个互斥量加锁。
当对互斥量解锁时,阻塞在该互斥量上的线程会被唤醒,它们竞争对该互斥量加锁,加锁成功的线程将停⽌阻塞,剩余的加锁失败于是继续阻塞。
注意到,谁将竞争成功是⽆法预料的,这⼀点就类似于弱信号量。
(强信号量把阻塞在信号量上的进程按时间排队,先进先出)互斥量区别于信号量的地⽅在于,互斥量只有两种状态,锁定和⾮锁定。
它不像信号量那样可以赋值,甚⾄可以是负值。
共性⽅⾯,我所体会到的就⼀句话,都是⽤来实现互斥的。
⾄于其它区别或联系,⽤不上,不作研究。
三. 读者优先只要有⼀个读者正在读,那么后续的读者都能⽴即读,不管有多少写者在等待。
可能导致写者饥饿。
1. 读者1) 写者写时,不可读2) 有别的读者正在读,可读2. 写者1) 有读者正在读,不可写2) 有写者正在写,不可写3) ⽆读者正在读,⽆写者正在写,可写四. 写者优先当新的写者希望写时,不允许该写者后续的读者访问数据区,但必须保证之前的读者读完。
1. 读者特点1) 有写者正在写或者等待写,须等到没有写者才能读2) 没有写者,可以读2. 写者特点1) 写者与写者互斥。
当其它写者正在写时,其它写者不能写。
2) 写者与读者互斥。
之前只有读者在读,当写者出现时,必须等到之前的读者都读完才能写。
java优先队列用法Java中的优先队列(PriorityQueue)是一种特殊的队列,它的元素按照优先级进行排序。
在优先队列中,元素可以通过自然排序(natural ordering)或者根据自定义的比较器(Comparator)进行排序。
优先队列经常用于解决一些优先级相关的问题,例如任务调度、事件处理等。
下面是一些关于Java优先队列的使用方法和相关参考内容。
创建优先队列:要使用优先队列,首先需要创建一个PriorityQueue对象,例如:```PriorityQueue<Integer> pq = new PriorityQueue<>();```上面的代码创建了一个容量为11的优先队列,并通过自然顺序进行元素排序。
可以通过指定Comparator来创建自定义排序的优先队列,例如:```PriorityQueue<Integer> pq = newPriorityQueue<>(Collections.reverseOrder());```上面的代码创建了一个降序排列的优先队列。
添加元素:可以使用add()或offer()方法将元素添加到优先队列中,例如:```pq.add(10);pq.offer(20);```在添加元素时,优先队列会根据元素的优先级进行排序。
获取队首元素:要获取优先队列中的队首元素,可以使用peek()方法,例如:```int firstElement = pq.peek();```peek()方法返回队首元素,但不会删除它。
删除队首元素:要删除优先队列中的队首元素,可以使用poll()方法,例如:```int firstElement = pq.poll();```poll()方法返回队首元素,并将其从优先队列中删除。
判断队列是否为空:要判断优先队列是否为空,可以使用isEmpty()方法,例如:```boolean isEmpty = pq.isEmpty();```isEmpty()方法返回true,表示队列为空;返回false,表示队列不为空。
多线程⾯试题系列(11):读者写者问题与上⼀篇的⽣产者消费者问题⼀样,读者写者也是⼀个⾮常著名的同步问题。
读者写者问题描述⾮常简单,有⼀个写者很多读者,多个读者可以同时读⽂件,但写者在写⽂件时不允许有读者在读⽂件,同样有读者在读⽂件时写者也不去能写⽂件。
上⾯是读者写者问题⽰意图,类似于的分析过程,⾸先来找找哪些是属于“等待”情况。
第⼀.写者要等到没有读者时才能去写⽂件。
第⼆.所有读者要等待写者完成写⽂件后才能去读⽂件。
找完“等待”情况后,再看看有没有要互斥访问的资源。
由于只有⼀个写者⽽读者们是可以共享的读⽂件,所以按题⽬要求并没有需要互斥访问的资源。
类似于上⼀篇中美观的彩⾊输出,我们对⽣产者输出代码进⾏了颜⾊设置(在控制台输出颜⾊设置参见《》)。
因此在这⾥要加个互斥访问,不然很有可能在写者线程将控制台颜⾊设置还原之前,读者线程就已经有输出了。
所以要对输出语句作个互斥访问处理,修改后的读者及写者的输出函数如下所⽰:[cpp]1. //读者线程输出函数2. void ReaderPrintf(char *pszFormat, ...)3. {4. va_list pArgList;5. va_start(pArgList, pszFormat);6. EnterCriticalSection(&g_cs);7. vfprintf(stdout, pszFormat, pArgList);8. LeaveCriticalSection(&g_cs);9. va_end(pArgList);10. }11. //写者线程输出函数12. void WriterPrintf(char *pszStr)13. {14. EnterCriticalSection(&g_cs);15. SetConsoleColor(FOREGROUND_GREEN);16. printf(" %s\n", pszStr);17. SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);18. LeaveCriticalSection(&g_cs);19. }读者线程输出函数所使⽤的可变参数详见《》。
读者写者问题 ----写者优先#include "windows.h"#include <conio.h>#include <stdlib.h>#include <fstream.h>#include <io.h>#include <string.h>#include <stdio.h>#define INTE_PER_SEC 1000 //每秒时钟中断的数目#define MAX_THREAD_NUM 64 //最大线程数#define MAX_FILE_NUM 32 //最大文件数目数#define MAX_STR_LEN 32 //字符串的长度FILE * file;FILE * inFile;int readcount=0; //读者数目int writecount=0; //写者数目//临界资源CRITICAL_SECTION cs_Write;CRITICAL_SECTION cs_Read;struct ThreadInfo{ int serial; //线程序号char entity; //线程类别(判断是读者还是写者线程) double delay; //线程延迟时间double persist; //线程读写操作时间};//写者优先---读者线程//P:读者线程信息void WP_ReaderThread(void *p){//互斥变量HANDLE h_Mutex1=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex1");HANDLE h_Mutex2=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex2");DWORD wait_for_mutex1; //等待互斥变量所有权DWORD wait_for_mutex2;DWORD m_delay=(DWORD)(((ThreadInfo*)(p))->delay *INTE_PER_SEC); //延迟时间DWORD m_persist=(DWORD)(((ThreadInfo*)(p))->persist *INTE_PER_SEC); //读文件持续时间int m_serial=((ThreadInfo*)(p))->serial ; //线程的序号Sleep(m_delay); //延迟等待printf("Reader thread %d sents the reading require.\n",m_serial);fprintf(file,"Reader thread %d sents the reading require.\n",m_serial);///////////wait_for_mutex1=WaitForSingleObject(h_Mutex1,-1);EnterCriticalSection(&cs_Read); //读者进去临界区//阻塞互斥对象Mutex2,保证对readCount的访问和修改互斥wait_for_mutex2=WaitForSingleObject(h_Mutex2,-1);readcount++;if(readcount==1){ // 如果是第1个读者,等待写者写完EnterCriticalSection(&cs_Write);}ReleaseMutex(h_Mutex2);// 释放互斥信号Mutex2//让其他读者进去临界区LeaveCriticalSection(&cs_Read);ReleaseMutex(h_Mutex1);//读文件printf("Reader thread %d begins to read file.\n",m_serial);fprintf(file,"Reader thread %d begins to read file.\n",m_serial);Sleep(m_persist);//退出线程printf("Reader thread %d finished reading file.\n",m_serial); fprintf(file,"Reader thread %d finished reading file.\n",m_serial);//阻塞互斥对象Mutex2,保证对readcount的访问,修改互斥wait_for_mutex2=WaitForSingleObject(h_Mutex2,-1); readcount--;if(readcount==0){ //最后一个读者,唤醒写者LeaveCriticalSection(&cs_Write);}ReleaseMutex(h_Mutex2); //释放互斥信号}/////////////////////////////////////////////写者优先---写者线程//P:写者线程信息void WP_WriterThread(void *p){DWORD wait_for_mutex3; //互斥变量DWORD m_delay; //延迟时间DWORD m_persist; //读文件持续时间int m_serial; //线程序号HANDLE h_Mutex3=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex3");//从参数中获得信息m_serial=((ThreadInfo*)(p))->serial ;m_delay=(DWORD)(((ThreadInfo*)(p))->delay *INTE_PER_SEC);m_persist=(DWORD)(((ThreadInfo*)(p))->persist *INTE_PER_SEC);Sleep(m_delay); //延迟等待printf("Writer thread %d sents the reading require.\n",m_serial);fprintf(file,"Writer thread %d sents the reading require.\n",m_serial);wait_for_mutex3=WaitForSingleObject(h_Mutex3,-1);writecount++; //修改写者数目if(writecount==1){EnterCriticalSection(&cs_Read);}ReleaseMutex(h_Mutex3);EnterCriticalSection(&cs_Write);printf("Writer thread %d begins to write to the file.\n",m_serial);fprintf(file,"Writer thread %d begins to write to the file.\n",m_serial);Sleep(m_persist);printf("Writer thread %d finished writing to the file.\n",m_serial);fprintf(file,"Writer thread %d finished writing to the file.\n",m_serial);LeaveCriticalSection(&cs_Write);wait_for_mutex3=WaitForSingleObject(h_Mutex3,-1);writecount--;if(writecount==0){LeaveCriticalSection(&cs_Read);}ReleaseMutex(h_Mutex3);}///////////////////////////////////////////////写者优先处理函数// file:文件名int main(int argc,char *argv[]){DWORD n_thread=0;DWORD thread_ID;DWORD wait_for_all;HANDLE h_Mutex1=CreateMutex(NULL,FALSE,"mutex1");HANDLE h_Mutex2=CreateMutex(NULL,FALSE,"mutex2");HANDLE h_Mutex3=CreateMutex(NULL,FALSE,"mutex3");HANDLE h_Thread[MAX_THREAD_NUM];ThreadInfo thread_info[MAX_THREAD_NUM];InitializeCriticalSection(&cs_Write);InitializeCriticalSection(&cs_Read);int a;char c;int b;int d;file=fopen("thread.txt","r");if(file!=NULL){while(!feof(file)){fscanf(file,"%d %c %d%d\n",&a,&c,&b,&d);thread_info[n_thread].serial=a;thread_info[n_thread].delay=b;thread_info[n_thread].entity=c;thread_info[n_thread++].persist=d;}}fclose(file);if((file=fopen("output.txt","w"))==NULL){cout<<"can not open the output.txt file"<<endl;}fprintf(file,"%s","start\n");for(int i=0;i<(int)(n_thread);i++){if(thread_info[i].entity=='R'||thread_info[i].entity =='r'){ //创建读者进程h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(WP_ReaderThread),& thread_info[i],0,&thread_ID);} else{ //创建写线程h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(WP_WriterThread),&t hread_info[i],0,&thread_ID);}}//等待所有的线程结束wait_for_all=WaitForMultipleObjects(n_thread,h_Thread,TRUE,-1);printf("All reader and writer have finished operating.\n");fclose(file);return 0;}。
读者写者问题⼀设计概述所谓读者写者问题,是指保证⼀个writer进程必须与其他进程互斥地访问共享对象的同步问题。
读者写者问题可以这样的描述,有⼀群写者和⼀群读者,写者在写同⼀本书,读者也在读这本书,多个读者可以同时读这本书,但是,只能有⼀个写者在写书,并且,读者必写者优先,也就是说,读者和写者同时提出请求时,读者优先。
当读者提出请求时需要有⼀个互斥操作,另外,需要有⼀个信号量S来当前是否可操作。
信号量机制是⽀持多道程序的并发操作系统设计中解决资源共享时进程间的同步与互斥的重要机制,⽽读者写者问题则是这⼀机制的⼀个经典范例。
与记录型信号量解决读者—写者问题不同,信号量机制它增加了⼀个限制,即最多允许RN个读者同时读。
为此,⼜引⼊了⼀个信号量L,并赋予初值为RN,通过执⾏wait(L,1,1)操作,来控制读者的数⽬,每当有⼀个读者进⼊时,就要执⾏wait(L,1,1)操作,使L的值减1。
当有RN个读者进⼊读后,L便减为0,第RN+1 个读者要进⼊读时,必然会因wait(L,1,1)操作失败⽽堵塞。
对利⽤信号量来解决读者—写者问题的描述如下:Var RN integer;L,mx:semaphore: =RN,1;BeginParbeginReader :beginRepeatSwait(L,1,1);Swait(mx,1,0);.Perform reader operation;Ssignal(L,1);Until false;EndWriter :beginRepeatSwait(mx ,1,1,l,RN,0);Perform writer operation;Ssignal(mx,1);Until false;EndParendEnd其中,Swait(mx,1,0)语句起着开关作⽤,只要⽆Writer进程进⼊些,mx=1,reader进程就都可以进⼊读。
但是要⼀旦有Writer进程进⼊写时,其MX=0,则任何reader进程就都⽆法进⼊读。
经典同步问题读者-写者问题读者-写者问题在读者-写者问题中,只对共享数据进⾏读取的进程为读者进程,修改共享数据的进程称为写者进程。
多个读者可同时读取共享数据⽽不会导致出现错误,但是任何时刻多个写者进程不能同时修改数据,写者进程和读者进程也不能同时访问共享数据。
读者-写者问题的解决策略有不同的倾向。
读者优先需要⽤到的共享变量:semaphore rw_mutex = 1; // 读者与写者互斥访问共享数据的互斥信号量semaphore mutex = 1; // 多个读者进程互斥修改当前读者进程数量的信号量int read_count = 0; // 系统当前读者进程数量写者进程结构do {wait(rw_mutex);.../* 修改共享数据 */...signal(rw_mutex);}while(true);读者进程结构do {wait(mutex); // 获取修改读者进程数量的互斥信号量,该操作在请求rw_mutex之前,防⽌出现死锁read_count++;if(read_count == 1) // 判断当前是否为第⼀个读者进程wait(rw_mutex); // 如果是就需要请求访问共享数据的互斥信号量signal(mutex); // read_count修改后释放信号量.../* 读取数据 */...wait(mutex); // 获取修改读者进程数量的互斥信号量read_count--;if(read_count == 0) // 判断当前进程是否为最后⼀个读者进程signal(rw_mutex); // 如果是则释放共享数据的互斥信号量,以允许写者进程操作共享数据signal(mutex);}while(true);读者优先有可能导致写者进程产⽣饥饿现象,当系统中不断出现读者进程时,写者进程始终⽆法进⼊临界区。
写者优先需要⽤到的共享变量:semaphore rw_mutex = 1; // 读者与写者互斥访问共享数据的互斥信号量semaphore r_mutex = 1; // 互斥修改当前读取⽂件的进程数semaphore w_mutex = 1; // 互斥修改当前修改⽂件的进程数semaphore enter_mutex = 1; // 获取申请访问⽂件的权限int read_count = 0; // 系统当前读者进程数量int write_count = 0; // 系统当前写者进程数量写者进程结构do {wait(w_mutex); // 新的写者进程进⼊,获取修改写者进程数量的权限write_count++;if(write_count == 1) // 判断当前是否为第⼀个写者进程wait(enter_mutex); // 阻断后续到达的读者进程signal(w_mutex);wait(rw_mutex); // 获取访问⽂件的权限,⽂件可能被其它写者进程占⽤,或者等待最后⼀个读者进程释放.../* 修改数据 */...wait(rw_mutex);wait(w_mutex);write_count--;if(write_count == 0) // 当所有写者进程都放弃使⽤⽂件时,运⾏读者进程申请访问⽂件signal(enter_mutex);signal(mutex);}while(true);读者进程结构do {wait(enter_mutex); // 获取申请访问⽂件的权限wait(r_mutex);read_count++;if(read_count == 1) // 判断当前是否为第⼀个读者进程wait(rw_mutex); // 占⽤⽂件signal(r_mutex);signal(enter_mutex);.../* 读取数据 */...wait(r_mutex);read_count--;if(read_count == 0)signal(rw_mutex);signal(r_mutex);}while(true);写者优先有可能导致读者进程产⽣饥饿现象,当系统中不断出现写者进程时,读者进程始终⽆法进⼊临界区。
读者优先级调度和写者优先级调度算法的改进江波【摘要】用P/V操作来解决操作系统中的读写者问题,是并发技术的基本功能.文章对读者具有优先权、写者具有优先权和读者/写者公平竞争算法进行研究,并对读者优先和写者优先算法进行改进.仿真实验表明,改进的算法在各种测试数据下能用正确的时序解决读写者问题,对临界资源的访问也是正确的.【期刊名称】《贺州学院学报》【年(卷),期】2010(026)002【总页数】4页(P122-125)【关键词】P/V操作;读者优先级调度;写者优先级调度;读者与写者公平竞争【作者】江波【作者单位】贺州学院,计算机科学与工程系,广西,贺州,542800【正文语种】中文【中图分类】TP316.4并发是操作系统的一个基本特征,是操作系统设计的基础[1]P157-169。
在早期的多道程序设计系统中,一个关键的问题就是要解决并发进程中的同步、互斥和死锁,这也是研究者所关注的热点[2]P203-206。
随着计算机技术和网络技术的不断发展,又涌现出对称多处理器和分布式操作系统(如集群系统、对等网络系统和网格等),同步和互斥在这些新出现的操作系统中也得到了扩充和更新[3]P58-72。
进程间通信是用P/V操作来实现读写者问题,其解决方案主要有读者具有优先权、写者具有优先权、读者与写者公平竞争方案[4]P65-69。
读/写者问题需要为数据库访问建立了一个模型:具有一个数据区(可以是一个文件、主存的一个空间块,或者是一组寄存器),多个进程可以其数据;存在一些只读数据进程(reader,读者)和一些写数据的进程(writer,写者)。
2.1 读者优先级调度读者优先级调度必须满足两个条件:2.1.1 有写者正在写数据时,读者必须等待。
2.1.2 无读者正在读数据时,写者才可以写数据。
为了满足这两个条件,引入记录当前正在运行的读者进程数(ReaderCount,全局整型量), ReaderCount赋初值0,当一个读者进程进入系统时,ReaderCount执行加1操作;当ReaderCount由0变为l时,表示第一个读者进程进入该系统,需要该读者进程对控制写者进程的互斥信号量mutex-wsem执行P操作,以便与写者进程互斥;当ReaderCount由非0值增加时,表示不是第一个读者进程进入系统,不需要再对互斥信号量mutex-wsem执行P操作;当有读者进程退出系统时,必须对ReaderCount执行减1操作;当如ReaderCount等于0时,表明最后一个读者进程退出系统,需要该读者进程对mutex-wsem执行V操作,让写者进程能够进入系统。
实验题目:实验五读者-写者问题完成人:报告日期:一、实验内容简要描述1)创建一个控制台进程,此进程包含n个线程。
用这n个线程来表示n个读者或写者。
每个线程按相应测试数据文件的要求进行读写操作。
用信号量机制分别实现读者优先和写者优先的读者-写者问题。
2)读者-写者问题的读写操作限制(包括读者优先和写者优先):写-写互斥,即不能有两个写者同时进行写操作。
读-写互斥,即不能同时有一个线程在读,而另一个线程在写。
●读-读允许,即可以有一个或多个读者在读。
3)读者优先的附加限制:如果一个读者申请进行读操作时已有另一个读者正在进行读操作,则该读者可直接开始读操作。
4)写者优先的附加限制:如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。
5)运行结果显示要求:要求在每个线程创建、发出读写操作申请、开始读写操作和结束读写操作时分别显示一行提示信息,以确定所有处理都遵守相应的读写操作限制。
二、程序设计1、设计思路将所有读者和所有写者分别存于一个读者等待队列和一个写者等待队列中,每当读允许时,就从读者队列中释放一个或多个读者线程进行读操作;每当写允许时,就从写者队列中释放一个写者进行写操作。
2、主要数据结构1)读者优先读者优先指的是除非有写者在写文件,否则读者不需要等待。
所以可以用一个整型变量read_count记录当前的读者数目,用于确定是否需要释放正在等待的写者线程(当read_count=0时,表明所有的读者读完,需要释放写者等待队列中的一个写者)。
每一个读者开始读文件时,必须修改read_count变量。
因此需要一个互斥对象mutex来实现对全局变量read_count修改时的互斥。
另外,为了实现写-写互斥,需要增加一个临界区对象write。
当写者发出写请求时,必须申请临界区对象的所有权。
通过这种方法,也可以实现读-写互斥,当read_count=l时(即第一个读者到来时),读者线程也必须申请临界区对象的所有权。
阅读者-写入者问题的java实现完成人::计本022班XXXXXXXXX报告日期:2004.10.21 小组成员责任分配情况:类Cushion, MainTest XXXXXXX负责编写类Reader, Writer, Critical, 实验报告XXX负责程序调试三人共同完成一.报告主要内容1.设计思路: (1).Critical类的功能主要是保存读写的互斥量,初始时将互斥量置零.Cushion类的功能是作为不能被执行的读写者的缓冲区使用Reader类创建一个读者线程Writer类创建一个写者进程(2)先随机产生一个读者/写者(3)检测读写互斥量,读者在写者互斥量为0时才可以被创建,否则进入等待队列,若该队列已满则读者离开;写者大抵相类似,不同的是写者进入之前需要检测读者和写者两个互斥量.(4)在创建读者/写者之时,由构造函数用start()启动线程,执行中以sleep()模拟操作.(5)在预设的来者次数结束后,检测等待的读写者队列,分别凊空..2.主要数据结构:等待队列由数组来实现3.主要代码结构(C++/Java:类图,类说明;C:函数调用图,函数原型,说明) 本试验用java完成.完成工具为JCreator 类结构如下图:4. 对难懂的代码段分析说明在类Cushion中,min()函数的功能是返回进入队列最早的读写者序号.delete()的功能则是在队列中删除已经出去的读写者序号.在类读者中,用了一个局部变量numu,其作用是保存静态变量的值,让读者的到达和离去序号一致,不会受到静态数据变化的影响;在类写者中也有起类似作用nunu变量.构造函数的多态表示是由于两次创建读写者时间不同(一次是开始时创建,一次是凊空的需要),为了让序号一致,所以调用不同的构造函数.二.实验结果1.基本数据(1)源程序代码行数: 206(2)完成实习投入的时间(小时数)每人15小时左右,(3)小组讨论次数:四次2.测试数据(输入)设计:数据是随机产生的,循环次数由一个为cout的局部变量控制3.测试结果(输出)分析:左图是读者先来的结果右图是写者先来的结果下面选取写者先到情况进行分析:写者0到达,读者0和1到达进入队列等待,写者1和2到达相继进入写者等待队列,读者2到达,写者3到达都相继进入队列等待,随后读者3写者4.5.6都进入队列三.实验体会1.实验过程中遇到的问题及解决过程错误分析:因为用布尔型互斥量来标志读者存在,所以当读者0执行时Rmutex置真,此时就可以让读者进而写者不进,后续读者进入,但不好的是,此时读者出的话,就会无意中修改Rmutex 的值使其为假,此时来一个写者的话,就会误认为此时没有读者在里面而进入,从而错误.解决方法:我们改变了设置布尔值作为互斥量的办法,改为用一个整型值作为计数,多一个读者时则加一,读者操作完成则减一,这样就能保证在读者为走光之前都没有写者能够执行.在数组的边界控制上出的问题,因为size和数组并没有直接挂钩,所以当size超标时没有问题,但一旦应用于数组时则报错,解决方法:严格控制size值的大小,不让它越界.2.实验体会和收获(1)先说好的一面,此次试验充分考察了我们编程实现现实问题的能力,对操作系统的相关知识也有了进一步的认识;(2)不足的地方在于:在编程方面,对于有计划的编写代码还缺乏经验,所以程序条理性比较差,在运用java编程的时候,对于语言相关的API的熟悉程度还不够,因此效率低下;在人员磨合上我们做的也实在不够,不能充分发挥小组人员的优势,常常需要比编程更多的时间来说明彼此的代码,也影响了进度.另外,由于我们错会了试验报告的意思,没有令读写操作全部从文件中读出再执行,作为补救,我们将sleep()时间的产生由读文件来产生.参考文献目录计算机操作系统汤子瀛等著Java编程思想Bruce·eckel著问题求解与编程概念Maureen Sprandkle 著说明:周五的试验课上,我们的做法显然没有得到老师的赞同,主要是我们没有按试验要求的去做,这是我们以后要努力改善的.后来我们又试着重做了一下,但是由于时间紧迫,尚有一些问题没有解决,都注明在test文件中.import java.io.*;import java.util.*;class Critical //define the critical{static int Rmutex;static int Wmutex;Critical(){Rmutex=0;Wmutex=0;}}class Writer extends Thread{static int NUNU=0; //Writer's numuberint nunu; //save the Writer's numberWriter(int z){Critical.Wmutex++; // if writer is exist,make the flag"Wmutex"=truenunu=z;System.out.println("Writer "+(nunu)+"write");start();}Writer(){Critical.Wmutex++; // if writer is exist,make the flag"Wmutex"=truenunu=NUNU;System.out.println("Writer "+(nunu)+"write");start();}public synchronized void run(){try{BufferedReader br =new BufferedReader(new FileReader("one.txt"));int m=Integer.parseInt(br.readLine());System.out.println("Writer"+nunu+" write time:"+Math.random()*m);m=(int)(Math.random()*m);sleep(m);}catch(InterruptedException e){System.out.println("wrong");}catch(IOException e){}System.out.println("W "+(nunu)+"out");Critical.Wmutex--; //if writer is out ,make the flag"Wmutex"=false }}class Reader extends Thread{static int NUMU=0; //Reader's numberint numu; //save reader's numuberReader(){Critical.Rmutex++;numu=NUMU;System.out.println("Reader"+numu+"read");start();}Reader(int z){Critical.Rmutex++;numu=z;System.out.println("Reader"+numu+"read");start();public synchronized void run(){try{BufferedReader br =new BufferedReader(new FileReader("one.txt"));int m=Integer.parseInt(br.readLine());System.out.println("Readr"+numu+" read time:"+Math.random()*m);m=(int)(Math.random()*m);sleep(m);}catch(InterruptedException e){System.out.println("wrong");}catch(IOException e){}System.out.println("R "+(numu)+"out");Critical.Rmutex--;}}class Cushion // as same as queue{public int size;public int a[]=new int[10];public void delete(int a[],int i) //delete the reader or writer from array{if(i==(size-1)){ size--;return;}else{for(int z=i;z<=(size-1);z++){a[z]=a[z+1];}size--;}}public int min(int a[]) //delete the least element{int min,tem=0;min=a[0];for(int i=0;i<size;i++){if(min>a[i]){min=a[i];tem=i;}}delete(a,tem);return min;}Cushion(){ size=0;}}public class MainTest //the class include "main" function{public static void main(String[] args)//throws IOException{Critical one=new Critical(); //save mutexCushion two=new Cushion(); //reader's arrayCushion three=new Cushion(); //writer's arrayint count=0; //control the circle is endwhile(true){count=count+1;if(count>100)break;double k=Math.random(); //decide the comer is writer or readerif(k<0.5){if(one.Wmutex!=0){if(two.size<9){System.out.println("Reader"+Reader.NUMU+"want come in reader's array");two.a[two.size++]=Reader.NUMU++; //if the Writer exist,add Reader into array}elseSystem.out.println("The Reader's memory isn't enough");}else{Reader read1=new Reader(); //else create a ReaderReader.NUMU++;}}else{if((one.Wmutex!=0) ||(one.Rmutex!=0)){if(three.size<9){System.out.println("Writer"+Writer.NUNU+"come in writer's array ");three.a[three.size++]=Writer.NUNU++;}elseSystem.out.println("The Writer's array isn't enough");}else{Writer writ1=new Writer();Writer.NUNU++;}}}System.out.println("reader clear");while(two.size!=0) //if the thread is dead,free the array{if(one.Wmutex==0){int z=two.min(two.a);Reader read =new Reader(z);}elsecontinue;}System.out.println("writer clear");while( three.size!=0 ){if(one.Wmutex==0 && one.Rmutex==0){int m=three.min(three.a);Writer writ =new Writer(m);}else continue;}}}。
实验一实验报告学号:20092128 姓名:徐卓远实验序号:1实验名称:用信号量来实现读者-写者问题实验目的:理解进程同步与互斥的概念,掌握用信号量来实现进程的同步与互斥。
实验设计及实现:为了实现读者和写者的读写过程,将每个读者和每个写者作为了一个单独的线程,所以设置了两个类,一个是读者类Reader,一个是写者类Writer.以读者类为例:一个读者的动作过程为由睡眠->等待->开始读->结束读->睡眠的一个循环过程,而一个写者的动作过程也为此.读者调用方法napping()进行等待,调用startRead()方法开始读,最后在调用endReading()方法结束读入,释放运行空间.写者同读者.但是为了实现读者写者之间的写-写互斥,读-写互斥,读-读允许,需要另外一个类Database,类中分别用关于读者的方法和写者的方法来控制读写之间的这种关系.首先要实现睡眠的方法napping(),读者和写者在睡眠过程都应该是一样的,只是他们睡眠的时间不同,所以只需写出一个方法:public static void napping() {int sleepTime = (int) (NAP_TIME * Math.random()); try {Thread.sleep(sleepTime * 1000);} catch (Exception e) {e.printStackTrace();}}在方法中,控制线程休眠随机的时间,由于每个读者或写者都是一个线程,而每个读者或写者他们工作休眠的时间都不一定相同,他们请求工作的时间也不一定相同,所以取了随机时间其次设置了读者的两个方法,开始读和结束读,由于这只是个模拟读写问题,所以只需要知道结果就行,就不用显示出他是怎么读的.在开始读中,当有写者在写时,读者需要等待wait(),在没有人在工作时,如果有写者和读者同时请求,那么就让写者先进,这是写者优先.所以这就归纳于一种情况, 当读者布尔变量dbReading为FALSE时,如果有需要工作的写者,那么读者就等待.当读者请求读入后,计数有多少读者需要工作的变量readerCount +1,如果这是第一个进入工作的读者就需要将显示是否有读者在工作的读者布尔变量变为TRUE.public synchronized int startRead() {if (dbReading == false) {while (writerCount > 0) {try {System.out.println("reader is waiting");wait();} catch (Exception e) {System.out.println(e.toString());e.printStackTrace();}}}++readerCount;if (readerCount == 1) {dbReading = true;}return readerCount;}读结束时,计数需要读的读者数-1,然后释放出空间给需要工作的人.public synchronized int endReading() {--readerCount;if (readerCount == 0) {dbReading = false;}notifyAll();//释放出空间System.out.println("one reader is done, reading.Count=" + readerCount);return readerCount;}第三,编写关于写者的开始写和结束写方法,在开始写方法中,首先要将计数需要写的变量writerCount+1,写者如果有读者或者有写者正在工作,那么就等待,如果没有就直接进入写,然后表示是否有写者在写的布尔变量dbWriting变为TRUEpublic synchronized void startWriting() {//控制写者开始进入写++writerCount;while (dbReading == true || dbWriting == true) {try {System.out.println("Writer is waiting");wait();} catch (Exception e) {System.out.println(e.toString());}}dbWriting = true;}结束时只需将writerCount-1和dbWriting为FALSE,然后释放出空间.public synchronized void endWriting() {//控制写者结束写入--writerCount;dbWriting = false;System.out.println("one writer is done, writing.Count=" + writerCount);notifyAll();}源代码及程序流程图主类:package rw;/**** @author xzy*/public class Main {public static void main(String[] args) {Database db=new Database();//实例化类Database为dbReader r1=new Reader(1,db);//实例化类Reader为r1Reader r2=new Reader(2,db);Reader r3=new Reader(3,db);Reader r4=new Reader(4,db);Writer w1=new Writer(1,db);//实例化类Writer为w1Writer w2=new Writer(2,db);r1.start();//读者1调用start()方法开始进入读写这个模拟环境中r2.start();r3.start();w1.start();r4.start();w2.start();}}Database类:package rw;/**** @author xzy*/public class Database {private static final int NAP_TIME = 5;private int readerCount;//变量计数需要读的读者private int writerCount;//变量计数需要写的写者private boolean dbReading;//表示是否有读者在读private boolean dbWriting;//表示是否有写者在写public Database() {readerCount = 0;//变量计数需要读的读者为0writerCount = 0;//变量计数需要写的写者为0dbReading = false;//表示没有读者正在读入dbWriting = false;//表示没有写者正在写入}public static void napping() {//控制睡眠的时间int sleepTime = (int) (NAP_TIME * Math.random());//睡眠时间随机try {Thread.sleep(sleepTime * 1000);} catch (Exception e) {e.printStackTrace();}}public synchronized int startRead() {//控制读者开始读if (dbReading == false) {//当没有读者在读时while (writerCount > 0) {//当有写者想写时try {System.out.println("reader is waiting");wait();//等待} catch (Exception e) {System.out.println(e.toString());e.printStackTrace();}}}++readerCount;//请求读入的读者数加一if (readerCount == 1) {dbReading = true;//标明有读者正在读}return readerCount;}public synchronized int endReading() {//控制读者结束读入--readerCount;if (readerCount == 0) {dbReading = false;}notifyAll();//释放出空间给其他的线程System.out.println("one reader is done, reading. Count=" + readerCount);return readerCount;}public synchronized void startWriting() {//控制写者开始进入写++writerCount;//想写的写者数加一while (dbReading == true || dbWriting == true) {//当有读者在读或者有写者在写时都得等待try {System.out.println("Writer is waiting");wait();} catch (Exception e) {System.out.println(e.toString());}}dbWriting = true;}public synchronized void endWriting() {//控制写者结束写入--writerCount;dbWriting = false;System.out.println("one writer is done, writing. Count=" + writerCount);notifyAll();}}Reader类:package rw;/**** @author xzy*/public class Reader extends Thread {private Database server;//设置一个Database变量用来控制该读者private int readerNum;//设置该读者的标志public Reader(int r, Database db) {readerNum = r;server = db;}@Overridepublic void run() {int c;while (true) {System.out.println("reader " + readerNum + " is sleeping");Database.napping();//表明读者正在睡眠状态System.out.println("reader " + readerNum + " wants to read");c = server.startRead();//读者开始请求读入工作System.out.println("reader " + readerNum + " is reading. Count=" + c);Database.napping();//读者处于工作阶段c = server.endReading();//读者结束工作System.out.println("It is reader " + readerNum + " who has done reading according to count=" + c);}}}Writer类:package rw;/**** @author xzy*/public class Writer extends Thread {private Database server;//设置一个Database变量用来控制该写者private int writerNum;//设置该写者的标志public Writer(int w, Database db) {writerNum = w;server = db;@Overridepublic void run() {while (true) {System.out.println("Writer " + writerNum + " is sleeping");Database.napping();//表明写者正在睡眠状态System.out.println("Writer " + writerNum + " wants to write");server.startWriting();//写者开始请求读入工作System.out.println("Writer " + writerNum + " is writing");Database.napping();//写者处于工作阶段server.endWriting();//写者结束工作System.out.println("It is Writer " + writerNum + " who has done writing .");}}}写者:实验当堂所要完成的事情:解决编译和运行出现的问题.编译过程中出现的问题及其相应解决:1.一个读者或者写者工作完时无法释放出空间给其他人解决:用了notifyall()方法,最开始只知道notify()方法,要释放出空间给所有人平等使用权利那么就必须用notifyall()方法.运行过程中出现的问题及其相应解决:1.实现了写者优先但是没有实现读读允许解决:加了一个判断if,如果没有读者读才做出写者优先的判断.实验总结通过本次实验,我对读者-写者的过程有了清楚的认识,对互斥和同步有了更深一步的了解,在最开始的实验中,我没有正确理解好写者优先,当有写者等待时,读者就不能进入了,这样就没有实现读读允许,意识到了后,加了个if判断解决了这一问题.在JA V A的线程的使用方法中,释放空间这个方法过去一直用的是notify(),但是由于一直是对单一的线程,这次实验中发现这个方法在这里不可行,所以即时查阅了资料用了notifyall()方法,总的来说,这次是操作系统的第一次实验,感觉最主要的是把脉络理清楚,写代码的工作要比理清脉络简单.。