oo第二次作业总结
一、从多线程的协同和同步控制方面,分析和总结三次作业
1、单电梯FCFS调度方案
第五次作业感觉是学习多线程的起手题目,并没有很复杂的逻辑关系,电梯的调度也是最简单的傻瓜调度。这里我设置了三个线程,虽然本次作业的调度器没有什么作用,但是还是按照要求打出来了;我使用了一个请求队列的类,用于存储请求,并作为处理输入线程与调度器线程的共享对象资源。调度器与电梯共享一个队列,电梯从队列中提取数据运行。这次作业较为简单,这里不再赘述。
UML图:
方法复杂度:
类的复杂度:
时序图如下:
2、单电梯ALS调度
要求可以捎带,所以只和第一次采用一个请求队列去处理感觉会很困难,查了一下电梯的调度算法,综合scan、look,als和等等其他算法,最后采用了look算法;我另开了一个楼层类,将请求队列里的数据按上行与下行分散在各个楼层中,这样处理的好处是在电梯运动的过程中,只需要访问当前楼层与电梯行进方向(上行或下行)对应的数组是否有人即可,如果其目的地会让电梯运行到更远的地方,就更新目的地的状态即可。但是不太好的地方在于如何让电梯动起来,即第一个让电梯运行起来的请求处理会麻烦。这里采用了look算法,即从最高的楼层往下遍历到最低的楼层查看下行的最高楼层的地方,从最低的楼层往上到最高楼层遍历寻找上行的最低的楼层,然后选择离电梯最近的那一个让电梯去接(这里不一定是最快的,对于某些情况会慢一些,但随机数据表现的还好)。然后对于一些特殊情况的处理,如电梯在一楼,本来要去接一个从5楼下行的人,过程中如果有6楼下行的人出现,理论上当然会去接,所以在运行过程中要不断刷新目的地是什么。多设置了输入处理与电梯两个线程。共享数据只有一个处理队列,电梯内部设置调度器实现。
UML图:
复杂度:
class复杂度:
由于调度器在电梯内部实现了,所以电梯的复杂度特别高,代码长度也因为配置了不同的访问方法而显得极其冗长。
时序图:
3、多电梯协同调度
这次的电梯数量增加了两个,增加了乘客数量限制、停靠楼层限制。这时需要保证电梯之间尽量并行,所以需要外设一个调度器用于给三个电梯分配数据。我用的调度方法仍是第二次的调度策略,通过调度器依据各个电梯的状态给各个电梯分配数据,然后电梯依靠自己已有的数据运行。这样的处理方法没有考虑到电梯之间的协作,理论上还只是三个电梯各干各的,所以效率不是很高。
有关数据的拆分,我采用的是用一个0-7三位二进制数据代表该楼层属于三个电梯的状态,然后通过两个楼层的&来判断是否需要转电梯,如果需要转电梯,我只是简单的选择最近的可以实现中转的地方。(本次作业没有想明白电梯之间的协作怎么才能有效执行,所以这个地方的选择也会慢一点)
UML图:
复杂度分析:
因为没有很好的考虑多电梯的协同运送,所以想在电梯数据的分配上尽量便捷一些,然后处理的过程变得特别麻烦使用了大量的条件语句,所以在计算给ABC三电梯的数据分配上复杂度很高。
时序图如下:
调度器逻辑如下:
二、BUG分析与寻找BUG的策略
自己的bug:第一次作业因为比较简单,所以没有发现bug,第二次的作业在课下的bug主要是调度的问题,最多的情况还是在电梯状态的改变上,因为我采用的算法有一步是不断变换目的地,但是没想到在换掉目的地后原本的楼层移动循环出现了问题。而且这个部分bug很难排查,花了我较多的时间。都二次作业互测没有测出bug。第三次作业因为调度方法更加复杂,我仍是在人员调度问题上出了问题,第一个就是满载的处理,其次是因为ABC楼层停靠特定,我的处理是在停靠楼层判断是不是该楼层对应的有人要下,在到达一个楼层不是其停靠楼层时,在遍历时会产生一个错误,算是自己的一个逻辑错误。第三次作业强测出现了一个线程不安全的错误,加了一个锁后就完成了(觉得好蠢)。
其他人的bug: 我是和舍友一起打了一个简易的随机生成数据并且定点投放,并对程序的输出进行一个比较简单的评判,只是对人的进出与输入进行对比的一个简易的评判代码。所以互测的时候也就是把代码打包后放进程序跑,把错误数据交上去就完了。第一次第二次作业没有发现其他人的问题,第三次找到了一位同学的一个bug,有一个数据没有运送到指定位置,目测应该是在转站的时候电梯没有正确更新状态导致的,虽然数据还在,但是电梯已经不会运行了,而调度器因为人员没有全部运送完成而不会结束,出现超时。
寻找bug的策略:首先就是程序硬莽一直跑,查看随机数据的正确性,这种测试方法能测出绝大多数bug,对于一般情况的正确性效果奇佳,但是同样因为数据的随机性,这种方法对边界情况测试很弱,这样的东西需要自己去构建数据去测试。线程安全这个东西我觉得真的可能要佛了。弄出来完全看运气,解决办法我觉得只能从根源上解决了,就得分析设计上的共享数据的锁问题,我觉得这样比代码不断尝试复现来的高效。
三、心得与体会
这三次作业让我学习到了多线程,感觉收获最多的也就是这一点,相关的锁操作、同步、进程状态变换等等。也对随机算法的认识提高了,随机生成数据要求代码的普适性很广,极端情况会少很多,因而这些特殊数据显得又不是太重要。对于如何结束一个多线程的程序也尝试多种不同的方法,比如第三次的作业我将数据拆分开,当电梯执行完以后会将第二段放回调度器的请求队列中,这样调度器就不能单单依靠队列为空就结束,引申出的思考也是学到了挺多东西,处理也更加熟练了。
在这个单元里,突然觉得打码找bug是一件很有意思的事情(疯了),可能是os的衬托?(同样是bug,自己的代码越看越欢喜,领养的os代码填空就怎么看怎么难受)