实验一实验报告学号: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()方法,总的来说,这次是操作系统的第一次实验,感觉最主要的是把脉络理清楚,写代码的工作要比理清脉络简单.。