OO第二单元总结

OO第二单元总结

第一次作业:单部电梯模拟运输(含捎带)

设计策略:在第一次作业中,作业要求是使用一部电梯完成运输乘客的任务。在这次作用中我采用了生产者消费者模式,将乘客的输入进程作为生产者,将电梯进程作为消费者,将Waiter(等待电梯的人序列)设为缓冲区。

UML类图

OO第二单元总结_第1张图片

本次作业,主要有三个线程,一个是主线程,一个是输入进程Input,一个是电梯调度线程Admin,还有People类来记录乘客的信息,Stop类用来判断电梯线程是否能在无人的情况下停止(即输入进程是否已经结束)。我个人认为这个布局还是比较合理的,没有什么比较多余的地方。

调度策略:ALS算法

结构分析

OO第二单元总结_第2张图片

 

OO第二单元总结_第3张图片

相较于第一单元的作业本次作业在复杂度的分布上更加平衡,没有哪一个类过于复杂的情况出现,显得更加“面向对象”了。

UML协作图:

 

OO第二单元总结_第4张图片

第二次作业:多部电梯合作

设计策略:在第二次作业中由于加入了多部电梯,且不知道具体运行的电梯数量,但是知道最大电梯数量为5,所以我采用开5个电梯线程,和五个缓冲区,读取电梯数量后,只往编号小于电梯数量的缓冲区中添加请求来实现目标。

UML类图:

OO第二单元总结_第5张图片

 

    这次作业的类其实跟上一次差不多,但是5个电梯线程之间的逻辑非常相似,代码的重复率也很高,似乎有点冗余,或许使用继承之类的方法能够解决这个问题,此外五个线程当中的交互没有体现出来,而且无论怎样很有可能都会存在线程在无意义的wait(线程本不应该启动但是却在wait),虽然效果是一样的,但是显得有些“呆板“,性能方面可能也会有些影响。

复杂度分析:

OO第二单元总结_第6张图片OO第二单元总结_第7张图片OO第二单元总结_第8张图片

 

在这次作业中计算电梯的下一层目标层复杂度较高,这是由于在第一次作业中的捎带策略不够好,在针对一些特定的样例时会出现RTLE的情况,所以在nextfloor方法中针对这种情况的多增加几层循环造成的,其他的方法复杂度还是比较平均的。

UML协作图:与第一次作业类似只是将电梯线程和缓冲区变为5个。

第三次作业:在第三次作业中涉及到了换乘问题,以及电梯的动态添加问题。

设计策略:关于电梯的动态添加用了与第二次作业类似的做法,即开6个线程但是不一定往里面添加请求,换乘问题在Input线程中解决,首先看他能不能能通过电梯直达,如果不能就将他看成两个编号相同的人(换乘层作为第一个人的终点,第二个人的起点)然后把第一个人放入请求中,第二个人先保留下来,等第一个人到达后在将第二任放入请求中。

OO第二单元总结_第9张图片

 

 

整体结构上与第二次作业类似(问题也是类似)。

复杂度分析:

 

OO第二单元总结_第10张图片OO第二单元总结_第11张图片

OO第二单元总结_第12张图片OO第二单元总结_第13张图片OO第二单元总结_第14张图片

在这次作业中由于输入输出以及运行时考虑到电梯的类型不同,对应的操作也会有所改方法或者变,所以复杂度比较高(这个或许能在开一个方法来解决?)

UML协作图:(简化为两个线程)
OO第二单元总结_第15张图片

自身BUG分析与hack策略:

在第一次作业的互测中由于调度算法的缺陷被形如(1-1-15,2-2-15。。。。)这样的数据hack到(RCTLE)后来针对这种极端情况改进了调度算法后解决,在第三次作业的互测和强测当中均出现了程序运行到某一条指令时出现冲突的情况(可能是因为两个操作之间没有sleep),加入一个sleep(10)后解决。

由于多线程的不稳定性在很多BUG上很难复现出来,而造成hack失败,所以如果像第一单元那样构造边界数据来进行hack可能成功率不是很高,但是可以考率使用特殊数据来hack他的调度算法来使他进行超时(尤其是第一次作业中超时的限定比较严格时),也可以通过观察他的代码构造来看是否能通过特殊的数据来使他陷入死锁。这两种方法的成功率相对于通过线程不稳定性来hack要高一些而且超时的数据往往也比较特殊,容易想到和构造。

心得体会:

本学期OO作业进度已经过半,在第二单元中感觉“面对对象”做得比第一单元要好一些(尽管架构还是比较冗余),可能是题材的原因(总感觉第一单元更像是单纯的JAVA程序设计),同时多线程的内容和OS课程相互之间有一个联系,似乎加深了对多线程安全性的一些理解,问题还是很多,主要是不太清楚哪里需要加锁,哪里可以不加,在作业中我是全都加了锁来确保进程安全,但是这又好像会影响多线程的效率,在研讨课上听其他同学分享的一些加锁方法,比如按照顺序加锁还是比较实用的,之后在课下再去尝试一下。另外多线程的调试是真的玄学,很多BUG不是欧皇(?)可能都发现不了,就算发现了,也不知道第二次改了之后有没有彻底解决这个问题(谁知道是BUG被修好了还是只是恰好没遇上?)有时候碰到死锁问题的时候还要一步步跟着进程在进程中使用print来观察是什么原因来导致了死锁,费时费力(好在评论区大佬的提醒下避免了一些bug)。其他进程之外的算法设计其实要比第一单元简单一些,但是进程确实难顶,测试方面由于强测是随机的,还比较好应对(一般情况下只要线程是安全的不超时就没有问题),但是互测有些的玄学错误、超时问题是真的难顶,动辄要大改算法,实在是惹不起(不过这也帮助我完善了自己的电梯代码)。

你可能感兴趣的:(OO第二单元总结)