BUAA OO 第二单元作业总结

BUAA OO 第二单元作业总结

一、题目简介

此单元作业为模拟多线程实时电梯系统,第五次作业为模拟各楼座的纵向电梯,第六次作业模拟纵向和横向电梯,第七次作业增加乘客的换乘请求

二、架构模式

(一)第五次作业

各个类如下所示:

|- MainClass:主类
|- Controller:电梯管理器,用于将请求分配到各座的调度器
|- InputHandler:输入线程
|- Dispatcher:调度器
|- Elevator:电梯线程
|- Output:线程安全的输出类

UML类图如下:

线程间协作关系如下:

InputHandler负责读入外部请求,将请求传入Controller并将请求分配给各个楼座的Dispatcher,最后由Elevator线程从Dispatcher中读取当前座的外部请求并开始运行、接人等操作。

调度器 Dispatcher 是线程间的共享对象,运用简单的生产者-消费者模型解决了这次作业。

(二)第六次作业

各个类如下所示:

|- MainClass:主类
|- Scheduler:总管理器
|- Controller:各座或各楼层电梯管理器
|- InputHandler:输入线程
|- Dispatcher:调度器
|- Factory:电梯工厂类
|- Elevator:电梯线程
	|- VerticalElevator:纵向电梯类
	|- HorizontalElevator:横向电梯类
|- Output:线程安全的输出类

UML类图如下:

线程间协作关系如下:

InputHandler负责读入外部请求,将增加电梯的请求传入Scheduler并将请求分配给对应楼座或楼层的Controller,新建对应的DispatcherElevator;将乘客请求传入Scheduler并将请求分配给对应楼座或楼层的Controller,各个Controller根据顺序分配给对应的Dispatcher,由Elevator线程从Dispatcher中读取当前座的外部请求并开始运行、接人等操作。

此次作业架构上和上次作业差异不大,只是多了一层管理器,在线程交互层面仍然是简单的生产者-消费者模型,在上次作业基础上迭代较为简单。

(三)第七次作业

各个类如下所示:

|- MainClass:主类
|- Scheduler:总管理器
|- Controller:各座或各楼层电梯管理器
|- InputHandler:输入线程
|- Dispatcher:调度器
|- Factory:电梯工厂类
|- Elevator:电梯线程
	|- VerticalElevator:纵向电梯类
	|- HorizontalElevator:横向电梯类
|- Person:可换乘的乘客请求
|- Output:线程安全的输出类

UML类图如下:

线程间协作关系如下:

此次作业相较上次作业增加换乘要求,增加了满足换乘要求的Person类,将一个请求拆分成多个请求,同时使用流水线架构,在Elevator中完成一部分,将未完成的请求通过Scheduler再次分配到对应的Dispatcher中,直到乘客最终到达目的地。

三、锁与同步块的设置

(一)第五次作业

此次作业中,我将调度器 Dispatcher设为共享对象,在Dispatcher类中的方法均带锁。

在电梯Elevator类中,因为要对Dispatcher中获取请求,就要对Dispatcher进行修改,所以在Elevator中只要对Dispatcher有访问,不管是读还是写均对Dispatcher设置了锁,相应的,在这些部分都设置了同步块。将同步块根据电梯的行为分成较小的块,防止电梯运行中长时间持有锁导致性能的下降。

在输出类Output中,考虑到线程安全,对其中的输出方法进行上锁,避免不同线程同时使用输出导致一些不可描述的错误。

(二)第六次作业

此次作业架构与上次作业没有太大差异,对共享对象的访问均上锁。

(三)第七次作业

此次作业因为使用了流水线模式,电梯完成请求的一部分后要将未完成的请求重新通过管理器分配,所以在总管理器Scheduler中对自己上了锁,避免新增指令和重新分配指令的冲突分配。

四、调度器设计

在三次作业中,调度器Dispatcher其实只是一个存储当前楼座或楼层外部请求的管理器,调度算法均实现在电梯中,实现了look算法,在每一层判断是否有要出和要进的人,没有则按照外部请求中最先到达的,向其前进。调度器起到的只是一个生产者InputHandler和消费者Elevator之间的“货架”作用。

五、程序的bug

(一)第五次作业

第五次作业因为架构比较简单,实现起来没有什么问题,主要在不断完善算法

(二)第六次作业

第六次作业发现了横向电梯死循环的bug,在当前方向还有请求时,由于横向环形电梯的特殊性,会想当前方向不停运动,为了解决这个问题,在横向电梯类中设置了一个标记属性,当电梯空载运行时标记加一,到三时转换电梯方向。

(三)第七次作业

此次作业出现的bug为测试时的不仔细导致,在根据电梯id分配请求时将判断id的条件写反了,虽然不懂为什么这样还能通过一些测试点,只能说中测和强测的数据并不十分合理。

六、Hack策略

(一)第五次作业

此次作业较为简单,没有hack到。

(二)第六次作业

此次作业由于没有考虑到死循环的问题,将这个问题用来hack他人,能有一定效果。

(三)第七次作业

没有hack别人。

七、心得体会

  • 共享对象的维护非常重要,对其的改写一定要加锁,同时要注意锁的顺序避免出现死锁

  • 对对象的wait操作一定要注意唤醒

  • 线程的结束条件要多注意,在第七次作业输入结束后但乘客还需换乘的情况下,不对线程做特殊处理可能会直接结束。

  • 完备的课下测试很重要,在后两次作业中都是吃了没有进行完备测试的亏,尤其是第七次作业出现的非常明显的错误。

posted @ 2022-04-27 19:14  OutlierXv  阅读(31)  评论(0编辑  收藏  举报