专业课程设计报告内容撰写参考模板.docx
《专业课程设计报告内容撰写参考模板.docx》由会员分享,可在线阅读,更多相关《专业课程设计报告内容撰写参考模板.docx(38页珍藏版)》请在冰豆网上搜索。
专业课程设计报告内容撰写参考模板
教师对学生的项目评分
——进程的同步与互斥
一、课题内容和要求
1、课题内容:
在一个班上有S个学生。
每个学生都要做一个项目,每一个项目由K个老师一起评分。
总共有M个老师。
每个老师最多给N个项目评分。
其中,S*K<=M*N。
在项目结束后,老师们提供T分钟用来检查学生们的项目。
检查每一个学生的项目需要用时D分钟。
其中,T>D。
每一个学生的项目由K个老师共同来检查。
在T分钟的时间段内,学生可以在任何时间进入教室(random),除了在最后的D分钟内。
所有的老师一直保持工作状态直到他检查完N个项目或者是T分钟过去后。
T分钟过去后,所有的老师和同学都必须离开教室。
另外,在T分钟结束前的D分钟内(即在最后的D分钟内),如果有任何老师或者是学生都处在没有任务的状态下,都必须离开教室,因为已经没有时间让他完成任务了(因为一个项目检查的时间是整整D分钟)。
当一个学生进入教室后,他立即开始找K个没有任务的老师(一次找一个老师,假如没有空闲的老师,则等到有老师为止),找齐K个老师之后给老师检查,然后离开教室。
刚开始每一个老师都是处于空闲状态直到他被学生找到,被学生找到后只能等待,直到学生找齐K个老师(在等待学生找其他老师的时间里,他是不能接受其他同学检查作业的请求的),当学生找齐K个老师后,老师们执行完检查任务,然后重新变成空闲状态。
每个老师在总共检查了N个学生的作业后,离开教室。
2、基本要求:
用一个程序来模拟上面描述的作业检查过程。
每一个学生和每一个老师应该用不同的线程来完成。
可以选用C、C++和Java作为开发语言,但是考虑到专业课程设计I的实验大纲,请尽可能使用Java语言。
3、提高要求:
(1)考虑到跨平台的特性,请尽量使用posix线程标准(采用该标准有额外的加分);
(2)实现良好的图形用户界面;
(3)在程序演示过程中能清晰的展示多个学生线程和多个老师线程的同步和互斥流程。
二、需求和思路分析
1、Java线程
由于Java具有平台无关性(“Writeonce,runanywhere”)和内置对多线程的支持(java.lang包中的Thread类),所以本次课程设计考虑采用Java语言编写线程,下面简单介绍一下可能用到的一些方法。
(1)start()
线程调用该方法将启动线程,使之从新建状态进入就绪队列排队,一旦轮到它来享用CPU资源时,就可以脱离创建它的主线程开始自己的生命周期了。
(2)run()
Thread类的run()方法与Runnable接口中的run()方法的功能和作用相同,都用来定义线程对象被调度之后所执行的操作,都是系统自动调用而用户程序不得引用的方法。
调用start()方法(从父类继承的方法)通知JVM,等待JVM将CPU使用权切换给该线程。
当JVM将CPU使用权切换给线程时,如果线程是Thread的子类创建的,该类中的run()方法没有具体内容,程序要在Thread类的子类中重写run()方法来覆盖父类的run()方法,run()方法规定了该线程的具体使命。
当run()方法执行完毕,线程就变成死亡状态。
在线程没有结束run()方法之前,不要再调用start()方法,否则将发生IllegalThreadStateException异常。
(3)sleep(intmillsecond)
线程使用CPU资源期间,执行了sleep(intmillsecond)方法,使当前线程进入休眠状态。
sleep(intmillsecond)方法是Thread类中的一个类方法,线程一旦执行了sleep(intmillsecond)方法,就立刻让出CPU的使用权,使当前线程处于中断状态。
经过参数millsecond指定的毫秒数之后,该线程就重新进到线程队列中排队等待CPU资源,以便从中断处继续执行。
如果线程在休眠时被打断,JVM就抛出InterruptedException异常。
因此必须在try-catch语句块中调用sleep(intmillsecond)方法。
(4)currentThread()
currentThread()方法是Thread类中的类方法,可以用类名调用,该方法返回当前正在使用CPU资源的线程。
(5)线程的同步
当使用多个线程来访问同一个数据时,非常容易出现线程安全问题(比如多个线程都在操作同一数据导致数据不一致),所以我们用同步机制来解决这些问题。
实现同步机制有两个方法:
a)同步代码块:
synchronized(同一个数据){} 同一个数据:
就是N条线程同时访问一个数据。
b)同步方法:
publicsynchronized数据返回类型方法名(){}使用synchronized来修饰某个方法,则该方法称为同步方法。
对于同步方法而言,无需显示指定同步监视器,同步方法的同步监视器是this也就是调用该同步方法的对象的本身
当使用synchronized来修饰某个共享资源时(分同步代码块和同步方法两种情况),当某个线程获得共享资源的锁后就可以执行相应的代码段,直到该线程运行完该代码段后才释放对该共享资源的锁,让其他线程有机会执行对该共享资源的修改。
当某个线程占有某个共享资源的锁时,如果另外一个线程也想获得这把锁运行就需要使用wait()和notify()/notifyAll()方法来进行线程通讯了
(6)wait()、notify()、notifyAll()
wait()、notify()、notifyAll()都是Object类中的final方法,被所有的类继承,且不允许重写。
wait()方法导致当前线程等待,直到其他线程调用同步监视器的notify()方法或notifyAll()方法来唤醒该线程。
notify()方法唤醒在同步监视器上等待的单个线程,如果所有线程都在同步监视器上等待,则会选择唤醒其中一个线程,选择是任意性的,只有当前线程放弃对该同步监视器的锁定后,也就是使用wait方法后,才可以执行被唤醒的线程。
notifyAll()方法唤醒在同步监视器上等待的所有的线程。
只用当前线程放弃对该同步监视器的锁定后,才可以执行被唤醒的线程。
(7)创建线程有两种方法,一是创建Thread子类以继承Thread类,但Java不支持多继承,灵活性不够好。
二是用Thread类直接创建线程对象,使用构造方法Thread(Runnabletarget)实现Runnable接口对于使用同一目标对象的线程,目标对象的成员变量就是这些线程共享的数据单元;另外,创建目标对象类在必要时还可以是某个特定类的子类。
正因此,使用Runnable接口比使用Thread的子类更具有灵活性。
所以,本次课程设计考虑采用实现Runnable接口的方法来创建老师和学生线程。
2、主线程模块
产生学生进入的随机时间;
全部老师进入教室;
学生进入教室;
等待;
时间T到达,退出程序;
3、学生线程模块
学生线程执行下面的步骤:
选择一个进入的时间(random()%T);
进入教室;
选择K个空闲的老师,若找不齐,则等待;
找齐后,做D分钟的检查;
检查完毕离开教室。
4、老师线程模块
老师线程执行下面的步骤:
在教室中空闲;
直到被一个学生选择后等待(所有K个老师聚集);
等待结束项目检查开始;
做D分钟的项目检查,返回
(1);
N次检查完毕或者T分钟时间到,离开教室。
5、注意事项:
在剩余时间小于D时,一个已创建的学生线程只能执行第(5)步,不能再创建新的学生线程;
在剩余时间小于D时,一个老师进程只能在执行(3)—(4)步或者直接执行第(5)步;
对于所有合理的S,M,K,N,T,D数值(这些数必须都是正整数并且满足条件:
S*K<=M*NandT>D),程序都能够运行成功;
程序对所有的时间安排策略都必须运行成功。
例如不管线程的相对速度,例如要把握好sleep的毫秒数;
在每一个线程的生命周期内,每一步都要有一个合理的说明信息,来表明这个线程中包括哪个老师,哪个学生,进行到什么程度了;
要特别注意防范死锁问题的发生。
三、概要设计
仔细分析课题,可以分为以下几个模块实现:
1、主线程
通过人机对话获得所需要的学生人数S,老师人数M,学生需要接受检查的老师数K,老师最多检查学生数N,总时间T,学生接受检查所需时间D。
调用随机函数产生学生线程产生的时间,接着创建ProjectCheck类实现Runnable接口产生老师线程,等老师线程全部产生,一旦学生线程产生时间一到立即产生学生线程,等待时间T到,结束所有未结束的学生和老师线程,退出程序。
2、ProjectCheck类
(1)成员变量:
intS,M,K,N,T,D;//学生人数S,老师人数M,学生需要接受检查的老师数K,老师最多检查学生数N,总时间T,学生接受检查所需时间D
intcountCurrentTeacher;//当前处于空闲状态的老师数目
staticlongtimeStart;//程序开始时间
booleanteacherBusy[];//老师当前忙闲状态
intteacherCountOfCheckedProject[];//当前已经检查过的项目数目
Threadteacher[];//老师线程
Threadstudent[];//学生线程
finalstaticintEMPTY=0;//状态“空”,没人进入或离开教室
finalstaticintCOMING=1;//状态“进入”,有人正在进入教室
finalstaticintLEAVING=2;//状态“离开”,有人正在离开教室
intstate;//教室当前状态
(2)成员函数:
publicstaticintgettime();//获取相对于timeStart的当前时间,以ms为单位
publicProjectCheck(intS,intM,intK,intN,intT,intD,longtimeStart);//构造函数,初始化一些成员变量
publicvoidrun();//重写接口中的方法
//保证同一时刻只有一人进入或者离开
publicsynchronizedvoidcomeLock();//有人进入“锁”
publicsynchronizedvoidleaveLock();//有人离开“锁”
publicsynchronizedvoidcomeUnlock();//有人进入“解锁”
publicsynchronizedvoidleaveUnlock();//有人离开“解锁”
publicvoidstartCheck(intid);//在run()方法中调用此方法,针对不同的老师线程、学生线程开始检查
(3)老师线程
老师线程的流程图如下图所示。
对老师进入上锁、解锁保证同一时刻只有一名老师进入,打印老师进入信息表明老师已进入教室,教室中处于空闲状态的老师人数加1。
接着利用while循环判断结束时间T是否到达和老师检查次数是否到达N,两个条件都不满足则继续循环判断那两个条件,老师即处于等待状态,否则如果老师检查学生的次数到达N,说明老师已完成规定的检查任务,已经离开,如果
时间T到达,说明所有线程都要结束,所以这两种情况都要跳出循环,准备离开。
最后对老师离开上锁、解锁保证同一时刻只有一名老师离开,打印老师离开信息,教室中处于空闲状态的老师人数减1。
老师线程结束。
(4)学生线程
判断当前时刻是否大于T-D,若大于则说明剩余时间不够老师检查,学生立即离开即学生线程结束,否则对学生进入上锁、解锁保证同一时刻只有一名学生进入,打印学生进入信息表明学生已经进入教室。
接着在寻找K个老师检查之前,先利用while循环判断目前教室中处于空闲状态的老师人数是否小于K,若小于表明目前该学生无法找到K个老师为他检查,则继续判断该条件,学生即处于等待状态,否则立即把教室中处于空闲状态的老师人数减去K,跳出循环,寻找K个老师检查。
学生等待过程中,若剩余时间不足D,则学生立即离开即学生线程结束。
寻找K个老师通过for循环K次,每次循环调用Random类的nextInt(M)方法寻找老师,利用while循环判断老师已检查次数是否到达N和老师是否正在检查别人即状态是否处于忙,两个条件只要有一个被满足,再调用Random类的nextInt(M)方法寻找老师,否则就立即修改老师的忙闲状态,保存老师序号。
找齐K个老师后,开始检查,调用Thread类的类方法sleep()阻塞时间D。
等检查完毕,利用K次for循环,将这K个老师的忙闲状态置闲,并把这些老师的检查次数加1,教室中处于空闲状态的老师人数加1。
最后对学生离开上锁、解锁保证同一时刻只有一名学生离开,打印学生离开信息。
学生线程结束。
学生线程的流程图如下图所示。
四、详细设计
源程序代码如下:
创建名为projectCheck的工程文件,创建名为projectCheck.java和Main.java的类文件。
projectCheck.java:
packagecom.sand;
importjava.util.Scanner;
importjava.util.Random;
importjava.awt.*;
importjava.lang.InterruptedException;
publicclassProjectCheckimplementsRunnable
{
intS,M,K,N,T,D;//学生人数S,老师人数M,学生需要接受检查的老师数K,老师最多检查学生数N,总时间T,学生接受检查所需时间D
intcountCurrentTeacher;//当前处于空闲状态的老师数目
staticlongtimeStart;//程序开始时间
booleanteacherBusy[];//老师当前忙闲状态
intteacherCountOfCheckedProject[];//当前已经检查过的项目数目
Threadteacher[];//老师线程
Threadstudent[];//学生线程
finalstaticintEMPTY=0;//状态“空”,没人进入或离开教室
finalstaticintCOMING=1;//状态“进入”,有人正在进入教室
finalstaticintLEAVING=2;//状态“离开”,有人正在离开教室
intstate;//教室当前状态
publicProjectCheck(intS,intM,intK,intN,intT,intD,longtimeStart)//构造函数,初始化一些成员变量
{
this.S=S;
this.M=M;
this.K=K;
this.N=N;
this.T=T;
this.D=D;
this.timeStart=timeStart;
state=EMPTY;
countCurrentTeacher=0;//初始化当前处于空闲状态的老师数目为0
inti;
teacherBusy=newboolean[M];
for(i=0;i{
teacherBusy[i]=false;//初始化老师的忙闲状态为空闲
}
teacherCountOfCheckedProject=newint[M];
for(i=0;i{
teacherCountOfCheckedProject[i]=0;//初始化老师的检查次数为0
}
teacher=newThread[M];//创建线程名为teacheri的老师线程
for(i=0;i{
teacher[i]=newThread(this,"teacher"+i);
}
student=newThread[S];///创建线程名为studenti的学生线程
for(i=0;i
{
student[i]=newThread(this,"student"+i);
}
}
publicstaticintgettime()//获取相对于timeStart的当前时间,以ms为单位
{
longtimeCurrent;
intduration;
timeCurrent=System.currentTimeMillis();
duration=(int)(timeCurrent-timeStart);
returnduration;
}
publicvoidrun()//重写接口中的方法
{
inti;
intmax;
while(true)
{
for(i=0;i{
if(Thread.currentThread().getName().equals("teacher"+i))
{
startCheck(i);
return;
}
}
for(i=0;i
{
if(Thread.currentThread().getName().equals("student"+i))
{
startCheck(i);
return;
}
}
}
}
//保证同一时刻只有一人进入或者离开
publicsynchronizedvoidcomeLock()//有人进入“锁”
{
if(state==EMPTY){
state=COMING;
}
elseif(state==COMING){
}
elseif(state==LEAVING){
try{
wait();
}catch(InterruptedExceptione){
}
state=COMING;
}
}
publicsynchronizedvoidleaveLock()//有人离开“锁”
{
if(state==EMPTY){
state=LEAVING;
}
elseif(state==LEAVING){
}
elseif(state==COMING){
try{
wait();
}catch(InterruptedExceptione){
}
state=LEAVING;
}
}
publicsynchronizedvoidcomeUnlock()//有人进入“解锁”
{
state=EMPTY;
notify();
}
publicsynchronizedvoidleaveUnlock()//有人离开“解锁”
{
state=EMPTY;
notify();
}
publicvoidstartCheck(intid)//针对不同的老师线程、学生线程开始检查
{
if(Thread.currentThread().getName().equals("teacher"+id))//老师线程所要完成的操作
{
comeLock();//使同一时刻只有一人进入或离开教室
countCurrentTeacher++;//教室中空闲老师人数加1
System.out.println(gettime()+"ms:
"+Thread.currentThread().getName()+"entersclassroom");//打印老师进入信息
comeUnlock();
//判断当前时间是否小于T并且老师检查次数是否小于N,若两者都满足,则继续等待,否则跳出循环。
while(teacherCountOfCheckedProject[id]leaveLock();////使同一时刻只有一人进入或离开教室
if(teacherCountOfCheckedProject[id]==N)//
{
System.out.println(gettime()+"ms:
"+Thread.currentThread().getName()+"exitsclassroom(finished"+N+"jobs)");//打印老师离开信息,完成规定项目检查数目
}
else
{
System.out.println(gettime()+"ms:
"+Thread.currentThread().getName()+"exitsclassroom(timeout)");//打印老师离开信息,超时
}
countCurrentTeacher--;//教室中空闲老师人数减1
leaveUnlock();
}
elseif(Thread.currentThread().getName().equals("student"+id))//学生线程所要完成的操作
{
if(gettime()>T-D)//剩余时间是否小于D
{
leaveLock();//是,则学生离开
System.out.println(gettime()+"ms:
"+Thread.currentThread().getName()+"doesnotneedtoenterclassroom(timeisnotenough)");//打印学生离开信息,时间不够
leaveUnlock();
return;//结束学生线程
}
else
{
comeLock();//不是,学生进入教室
System.out.println(gettime()+"ms:
"+Thread.currentThread().getName()+"entersclassroom");//打印学生进入信息
comeUnlock();
}
synchronized(this)
{
while(countCurrentTeacher{
if(gettime()>T-D)//等待过程中,若剩余时间小于D,则结束等待,退出教室
{
comeLock();
System.out.println(gettime()+"ms:
"+Thread.currentThread().getName()+"exitsclassroom(timeisnotenough)");
comeUnlock();
return;
}
}
//目前教室中