OO第二单元(多线程电梯)
1.同步块的设置和锁的选择
1.1第五次作业
第五次作业参考了课上实验3的设计,InputThread线程读入数据,Controller控制人的进出和电梯移动,共享对象只有waitQueue。
同步块的设计:读入信息——人员分配
InputThread和Controller共享WaitQueue,读入请求和处理请求时需要加锁。因为第一次写的电梯完全由Controller控制,电梯只是一个能被操纵的机械装置,只有InputThread和Controller两个线程,所以进出电梯和电梯上下都由Controller控制。
1.2第六次作业
这一次作业重构了。
-
输入线程增加了加电梯的操作。
-
删掉了只能控制一个电梯的Controller,增加Scheduler线程,对读入的请求进行调度。
-
增加电梯线程,电梯不再是一个空壳,而是可以有自己id运行逻辑的电梯。
同步块
-
读入请求——请求分配——请求退回
共享WaitQueue,将输入的请求加入WaitQueue、调度器对WaitQueue中的请求进行分配以及有新电梯时所有电梯将当前未上电梯的人退回调度器时需要加锁。
-
请求分配——电梯运行
共享每个电梯独有的等待序列,调度器根据电梯状态选择合适的电梯,将WaitQueue中的请求加入到合适的电梯的等待序列中,电梯从自己的等待序列中获取请求并运送。调度器和电梯修改电梯的等待序列是需要加锁。
1.3第七次作业
相比上一次作业只修改了策略和结束条件,在此不再赘述。
2.调度器设计
2.1第五次作业
第五次作业我写的电梯非常愚蠢,并不是一个线程,而是一个只会开关关门和上下移动的机器,不能自己控制自己。我的“调度器”按照ALS捎带策略控制电梯的运行。
2.2第六次作业
增加多部电梯后,我的调度器分配时先遍历WaitQueue,为每个请求分配合适的电梯。具体分配时,调度器查看当前所有电梯的状态,计算权重,然后分配给权重最小的电梯。

对权重的计算比较粗略,初始为0,加上当前电梯乘客数和与当前楼层的距离,如果运行方向相反,则权重翻倍。这样计算虽然粗略,但较为简单,适用于所有电梯,分配情况也不会太差。
2.3第七次作业
沿用了上一次作业的调度器,分配策略没有改动,算权重方法不变,只是根据电梯可停靠楼层增加了能否接人的判断,如果某部电梯不能在这层停留,无论权重大小都被忽略。
因为我的调度器在分配请求时不会考虑是否能直达,所以在乘客进电梯后才会知道他需不需要换乘,换乘时电梯会生成一个新的请求给调度器,让调度器重新分配这个请求。
3.可扩展性
3.1第五次作业
本来写电梯的时候想着电梯越简单下一次作业越好扩展,所以写了一个甚至不会自己动的电梯,而是靠Controller不停调用电梯来控制电梯的运行,而且Controller仅能控制一部电梯。到了下一次作业多部电梯就这样发现行不通了
- UML类图

- UML顺序图

3.2第六次作业
这次重构之后个人感觉可扩展性相比第五次作业好了不少,至少考虑到了下一次作业增加新功能时不需要修改太多。
-
UML类图
![]()
-
UML顺序图
![]()
输入线程负责读入请求并将请求给调度器。
调度器只负责根据策略将请求分配给不同的电梯。
电梯有自己的等待序列,只需要根据自己的运行逻辑完成自己专属等待序列和乘客的运送。
个人认为这一次的可扩展性较好,也可以根据需要方便地修改调度器的分配策略,而不会对电梯造成影响。
3.3第七次作业
第七次作业基本沿用了第六次作业的设计,仅增加了对电梯能否接人的判断,可扩展性尚可。
4.自己程序的bug
4.1第五次作业
Controller每拿到一个请求就会锁住WaitQueue,然后直到送达才会放锁,于是我的电梯实际上只完成了一个单线程程序的功能,一次只能送一个人。后来增加了EleQueue,Controller从WaitQueue中拿出请求后不直接处理,而是存入EleQueue,在对EleQueue中的请求进行处理,最后赶在ddl前实现了能送多人的电梯。
4.2第六次作业
-
死锁问题
![]()
如上图,alloc是电梯的专属等待序列,scheduleWait是调度器的等待序列,在需要退回请求时电梯会先锁住自己的等待序列,再锁住调度器的,而在调度器分配时,则会反过来,于是就出现了死锁问题。
-
电梯卡死
当有新电梯加入时,所有电梯会收到通知需要退回自己的等待序列的信号,退回后这个信号解除,当有电梯此时等待序列为空时,无法退回无法解除该信号,于是电梯停在这个状态不能动也不能结束
-
人未送完
没有增加电梯退回请求的机制时,调度器在收到输入结束信号并分配完请求后自动结束,增加退回机制后出现了电梯在输入结束,调度器为空,送完自己的序列后结束了。但是其他电梯未结束并将请求退回给了调度器,调度器将这些请求分配到了已结束的电梯,这些请求就不能再被送达了。
4.3第七次作业
-
死锁问题
因为加锁的顺序问题,依然出现了死锁问题。
-
结束条件误判
出现过人已全部送完但程序未结束的情况。调度器的结束条件和电梯的结束条件都应当是所有等待序列和电梯都为空且输入结束。
-
电梯方向误判
C类电梯在运送目的为15-17层的乘客时,按我的策略本应送到18层,但是在到达目的楼层后电梯根据当前乘客目的地判断此处应该停下,但是电梯本身的性质不允许它停,出现了卡死在某一层的情况。
5.发现别人程序bug所采用的策略
自己的bug都找得艰难,没有看别人的代码,发现错误也难以复现,所以没有找别人的bug。
6.心得体会
理论课上听多线程自以为领悟了,写起来发现完全是两回事。写作业前想了很久翻遍课件和课上的代码依然觉得无从下手,最后按照上机实验的代码多少领悟了一点多线程,才能真正开始着手写。
第五次作业还不明白加锁的意思,稀里糊涂的写完了自以为能跑起来就是胜利。
每次周六半夜还没过中测是都以为这次作业要无效了,最后总是在周日ddl前AC,心理承受能力大幅提高。
虽然写的着实艰难,但是收获和成就感也是真的不少,后两次作业看到强测都AC时觉得自己确实是有进步的。




浙公网安备 33010602011771号