基于信号量与P/V操作同步机制的读者/写者问题的设计与实现 (写者优先)
在操作系统课程设计中,老师给了这样一个题目,并且要求以GUI的形式模拟整个操作过程。所以,首先映入我脑海的语言便是JAVA。主意敲定,开始构思,如何用JAVA来巧妙地表现这种机制,尽管Java提供了synchronized,Semaphore等关键词,但在构思过程中依然是困难的。
建立读者类和写者类,建立之后为了实现写者优先需设定五个信号量,然而这五个信号量是在两个类中交替出现的,而且要保证原子性。不得已将这五个类全部放在主类中,设为静态变量。由此在另外两个类应用时很繁琐。
五个信号量:
public static Semaphore readCountSemaphore=new Semaphore(1); //读者数量更改,保持原子性
public static Semaphore writeSemaphore=new Semaphore(1);
//写者信号量
public static Semaphore reader_wait=new Semaphore(1); //读者信号量
public static Semaphore first_reader_wait=new Semaphore(1);//第一个读者,为了实现写者优先
public static Semaphore writerCountSemaphore=new Semaphore(1);//写者数量更改,保持原子性
完整代码:
主类:
package com; import java.awt.BorderLayout; import java.util.Random; import java.util.Scanner; import java.util.concurrent.Semaphore; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.JTextPane; import javax.swing.text.BadLocationException; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; public class ReadAndWrite extends JFrame { public static int countReader; //手动设置读者数 public static int countWriter; //手动设置写者数 public static int readCount=0; //等待读者数量 public static int writeCount=0; //等待写者数量 public static Semaphore readCountSemaphore=new Semaphore(1); //读者数量更改,保持原子性 public static Semaphore writeSemaphore=new Semaphore(1); //写者信号量 public static Semaphore reader_wait=new Semaphore(1); //读者信号量 public static Semaphore first_reader_wait=new Semaphore(1);//第一个读者,为了实现写者优先 public static Semaphore writerCountSemaphore=new Semaphore(1);//写者数量更改,保持原子性 //GUI static JTextField textfield1, textfield2, textfield3,textfield4; JPanel panel, panel1, panel2; JLabel label1, label2, label3, label4; static JTextPane textpane; public ReadAndWrite(){ Scanner sc = new Scanner(System.in);//用来输入读写者个数 System.out.println("读者个数:"); countReader = sc.nextInt(); System.out.println("写者个数:"); countWriter = sc.nextInt(); textpane = new JTextPane();//动态执行界面 label1 = new JLabel("书:"); label2 = new JLabel("等待读者个数:"); label3 = new JLabel("等待写者个数:"); textfield1 = new JTextField(10);//显示谁正在对数据操作 textfield2 = new JTextField(10);//显示剩余读者个数 textfield3 = new JTextField(10);//显示剩余写者个数 panel1 = new JPanel(); panel1.add(label1); panel1.add(textfield1); panel1.add(label2); panel1.add(textfield2); panel1.add(label3); panel1.add(textfield3); JLabel label4 = new JLabel("正在等待读写者:"); textfield4 = new JTextField(44);//显示读写者的先后顺序 panel2 = new JPanel(); panel2.add(label4); panel2.add(textfield4); panel = new JPanel(new BorderLayout()); panel.add(panel1,BorderLayout.NORTH); panel.add(panel2,BorderLayout.SOUTH); panel.add(new JScrollPane(textpane),BorderLayout.CENTER); setTitle("读写者问题");//将此窗体的标题设置为指定的字符串 setBounds(300, 300, 600, 400); this.add(panel); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); this.setResizable(false); } public static void insert(String str)//向textpane中插入动态信息 { SimpleAttributeSet set = new SimpleAttributeSet(); StyleConstants.setUnderline(set, true); try { textpane.getDocument().insertString(textpane.getDocument().getLength(), str + "\n", set); } catch (BadLocationException e) { e.printStackTrace(); } } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub ReadAndWrite raw = new ReadAndWrite(); int i = 1; int j = 1; while(i<=ReadAndWrite.countReader||j<=ReadAndWrite.countWriter){ if(new Random().nextBoolean()){ //随机判断读写者 if(i>ReadAndWrite.countReader) continue; ReadAndWrite.insert("读者R"+i+"来了"); raw.textfield4.setText(raw.textfield4.getText()+"R"+i+","); new ReadThread(i); i++; } else{ if(j>ReadAndWrite.countWriter) continue; ReadAndWrite.insert("读者W"+j+"来了"); raw.textfield4.setText(raw.textfield4.getText()+"W"+j+","); new WriteThread(j); j++; } } } }读者类:
package com; import java.util.Random; //import java.util.concurrent.Semaphore; public class ReadThread extends Thread { public int id; public ReadThread(int id) { this.id = id; this.start(); } public void run() { try{ synchronized(this){ if(ReadAndWrite.writeSemaphore.availablePermits()>0)//判断是否有写者正在操作 ReadAndWrite.insert("读者R"+id+"可以读"); else ReadAndWrite.insert("有写者在写操作,读者R"+id+"等待读"); ReadAndWrite.reader_wait.acquire();//阻塞第一个之后的读者 ReadAndWrite.first_reader_wait.acquire();//第一个读者申请资源,为了写者优先 ReadAndWrite.readCountSemaphore.acquire();//保持writeCount的原子性 if(ReadAndWrite.readCount==0) ReadAndWrite.writeSemaphore.acquire(); ReadAndWrite.readCount++; ReadAndWrite.textfield2.setText(" "+ReadAndWrite.readCount);//GUI显示 ReadAndWrite.readCountSemaphore.release(); ReadAndWrite.first_reader_wait.release(); ReadAndWrite.reader_wait.release(); ReadAndWrite.insert("R"+id+"读文件");//GUI显示 ReadAndWrite.textfield1.setText("读者R"+id); Thread.sleep((long) (new Random().nextFloat()*2000)); ReadAndWrite.insert("读者R"+id+"读完了"); ReadAndWrite.readCountSemaphore.acquire(); ReadAndWrite.readCount--; ReadAndWrite.textfield2.setText(" "+ReadAndWrite.readCount); if(ReadAndWrite.readCount==0) ReadAndWrite.writeSemaphore.release(); ReadAndWrite.readCountSemaphore.release(); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }写者类:
package com; import java.util.Random; public class WriteThread extends Thread { public int id; public WriteThread(int id) { this.id=id; this.start(); } public void run() { try{ synchronized(this){ if(ReadAndWrite.writeSemaphore.availablePermits()>0)//判断是否有写者正在操作 ReadAndWrite.insert("写者W"+this.id+"可以写"); else ReadAndWrite.insert("写者W"+this.id+"不可以写"); ReadAndWrite.writerCountSemaphore.acquire();//保持writeCount的原子性 if(ReadAndWrite.writeCount==0) ReadAndWrite.first_reader_wait.acquire(); //如果写者数量为0,第一个读者申请访问 ReadAndWrite.writeCount++; ReadAndWrite.textfield3.setText(" "+ReadAndWrite.writeCount);//GUI显示 ReadAndWrite.writerCountSemaphore.release(); ReadAndWrite.writeSemaphore.acquire();//写者开始操作,与其他操作互斥 ReadAndWrite.insert("写者W"+this.id+"正在写");//GUI显示 ReadAndWrite.textfield1.setText("写者W"+id); Thread.sleep((long) (new Random().nextFloat()*2000)); ReadAndWrite.insert("写者W"+this.id+"写完了"); ReadAndWrite.writeSemaphore.release(); ReadAndWrite.writerCountSemaphore.acquire(); ReadAndWrite.writeCount--; ReadAndWrite.textfield3.setText(" "+ReadAndWrite.writeCount); if(ReadAndWrite.writeCount==0)//如果写者数量为0,唤醒第一个等待的读者 ReadAndWrite.first_reader_wait.release(); ReadAndWrite.writerCountSemaphore.release(); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
PS:这是第一次在CSDN记录我自己编程的过程,自知写的蹩脚的很,既然迈出了这一步,就等着接受唾沫。雄关漫道真如铁,走你!