BUAA-OO-Unit2单元总结

BUAA-OO-Unit2总结

一、作业要求

​ 我们要模拟的电梯系统是一个类似北京航空航天大学新主楼的电梯系统,楼座内有多部电梯,电梯可以在楼座内1-11层之间运行。系统从标准输入中读入乘客请求信息(起点层,终点楼层),请求调度器会根据此时电梯运行情况(电梯所在楼层,运行方向等)将乘客请求合理分配给某部电梯,然后被分配请求的电梯会经过上下行,开关门,乘客进入/离开电梯等动作将乘客从起点层运送到终点层。

​ 可以采用任何调度策略,即任意时刻,系统选择上下行动,是否在某层开关门,乘客分配给哪部电梯都可以自定义,只要保证在电梯系统运行时间不超过题目要求时间上限的前提下将所有的乘客送至目的地即可。

​ 其中,hw5的每个要求指定电梯编号,hw6取消这一限制,并加入reset请求,hw7增加双轿厢电梯相关设置。

二、作业迭代

1.hw5
UML图

在这里插入图片描述

架构分析
  • Main类:用于创建inputThread,Elevator,Scheduler线程并start
  • RequestQueue类:记录所有请求的共享队列waitQueue,以及各个电梯的请求队列requestQueue
  • InputThread类:用于读取输入,输入结束后进行setEnd控制其他线程结束。
  • Scheduler类:用于将waitQueue中的请求调度给电梯,本次作业直接按给定编号进行分配
  • Elevator类:本次作业核心类,实现了move,open等电梯行为
  • Strategy类:电梯的运行策略类,根据电梯当前各项属性返回电梯运行操作
  • Command类:枚举电梯的行为类,包括MOVE, OPEN, REVERSE
电梯运行策略

​ 采用了LOOK算法,每次先判断电梯的请求队列是否为空,电梯内是否有人,若均无且输入未结束则wait,否则over;接着利用strategy类返回电梯需要的操作:若需要下乘客或者上乘客——from楼层为curFloor且方向与运行方向一致——则open并先下后上再close;若电梯内无乘客且运行方向前方没有需要上电梯的乘客,则变更运行方向;否则move

同步块和锁的选择

​ 共享变量均来自于类RequestQueue,故需要给这个类的所有读写操作家伙加上锁以及notifyAll(),同时,在Elevator中所有涉及读写共享变量requestQueue的代码块中均使用synchronized关键字进行同步控制。作业中没有选择使用读写锁,均使用了synchronized。

2.hw6
UML图

在这里插入图片描述

架构分析

​ 本次作业大体上没有修改架构设计,在原来的基础上加入了resetRequest的处理。在InputThread中,根据请求种类初步分类,乘客请求加入waitqueue进行调度,重置请求直接分给对应电梯,相应地,在电梯中加入isReset属性,并存储一条resetRequest,给command加上reset命令,以便于strategy决定电梯下一步运行状态。

​ 特别地,由于reset可能会在strategy已经决定后到达电梯,这可能导致电梯继续执行其他操作而超过要求的reset时间,这一问题在互测中被发现。相应的修复为在电梯具体执行操作时多加入几处判断是否isReset。

调度策略

​ 本次作业采用了简单但有效的调度策略——平均分配策略。一开始,再考虑到reset时不能receive,而且强测时可能会出现一部电梯始终处于reset导致请求分配后无法完成,故在分配时跳过了正在reset的电梯。而电梯进行reset时将所有乘客赶出,但是不会调度给其他电梯,而是重置结束后全部再次receive并拉客。

​ 这一策略在以下情景会出现严重问题——同时重置五部电梯,再瞬间投入所有请求,这使得一部电梯承受了所有请求。这一bug在互测房间也十分常见,以至于在A房间出现了人人成功率大于30%的情况。

​ 在bug修复时,我更改了receive策略,在scheduler分配请求时,完全按照请求顺序依次分配给1-6号电梯,若电梯正处于reset状态则不输出receive,而交由重置结束后的receiveAll()进行receive。这样的改动在大部分强测和互测样例中均取得了不错的成绩,甚至有许多100的性能分,并不比其他复杂的影子电梯等策略弱多少。

同步块的设置和锁的选择

​ 对于reset实现的新增代码块中涉及读写requestQueue的语句进行同步控制,对requesQueue中新增方法进行同步控制

3.hw7
UML图与时序图

在这里插入图片描述

三次作业的时序图

架构设计

​ 本次新增双轿厢电梯。我的改动是在接收DCreset请求时直接新建buddy电梯,并添加对应的新创建方法,两轿厢共享请求列表。在strategy中新增TRANS换乘操作——换乘层上/下一层 - move - open - out - receive - reverse - in - move。相当于打包了一整个操作。相应的在strategy中加入判断是否可以进入换乘、是否需要换乘。对于那些下车的,若需要另一轿厢接送,则进行另一轿厢的receive。对于需要换乘而换乘楼层被占用的情况,则进入wait等待buddy轿厢唤醒。

​ 由于共享请求列表,无法沿用之前的wait判断条件。我顺势将wait和over指令整合进strategy并进行判断,根据请求队列中from to楼层判断是否有这一轿厢需要操作的请求,若无则进入wait。而over也不能仅看当前轿厢请求状态,需要两个轿厢同时满足over条件,否则可能出现其中一个轿厢提前异常结束的情况

调度策略

​ 本次仍然沿用之前的调度策略,但是不能在调度器中输出receive,因此将receive调整到elevator的方法中。特别的,对于那些from楼层为换乘层的请求,要注意不能在换乘时错误地重复receive。

同步块的设置和锁的选择

​ 对于reset和双轿厢实现的新增代码块中涉及读写requestQueue的语句进行同步控制,对requesQueue中新增方法进行同步控制

4.稳定和易变的内容
  • 稳定的内容:
    • 任务处理时序基本不变,InputThread输入解析,请求直接给电梯或者给scheduler进行调度,调度器将请求分配给电梯由电梯进行处理
    • 调度策略不变,均可以采用相同的调度策略完成
    • 电梯的运行策略不变,均采用LOOK策略,每次新增电梯操作不需要改变之前的内容
  • 易变的内容:
    • 电梯的运行操作,每次作业均有新增
    • 电梯的receive输出方式,hw6reset后需要重新receive,hw7双轿厢每次换乘均需要重新receive。
    • 电梯停止运行的条件:hw7中需要双轿厢同时满足over条件才可以进行over,wait条件也发生了变化。

三、bug分析与心得体会

​ 多线程的bug主要分类两方面,其中之一是方法的设计导致的bug,例如hw6中的调度不合理,以及hw7中出现的重复receive或漏receive的情况;另一方面是由多线程同步控制导致的bug,三次作业中均出现了由于同步控制不到位产生的例如currentModification等error。

​ 对于第一类bug,主要通过测评机给出的错误信息进行追踪,观察对应电梯产生bug的原因,这方面,使用同学的评测机DPO OJ给了我很大的帮助。

对于第一类bug,主要通过测评机给出的错误信息进行追踪,观察对应电梯产生bug的原因,这方面,使用同学的评测机DPO OJ给了我很大的帮助。

​ 对于第二类bug,实际上是我对于线程安全的控制意识不够到位导致的。需要找出程序中所有的共享变量并设置同步块保证线程互斥,而我在写作业时,对于那些涉及共享变量的方法和代码块没有意识到需要控制,都是评测后才会意识到。同时,可能存在一些隐形的藏在方法调用中的线程安全问题我没有发现,这些问题最好在写的时候就意识到。

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值