2022 OO 第二单元个人总结

2022 OO 第二单元个人总结

个人认为在本单元作业中,贯穿三次作业的难点有两个内容:线程安全调度算法

一、同步块的设置和锁的选择

1. 为什么设置锁、锁的选择

是用来保证线程安全的,对于共享对象,我们需要在其被使用时对其加锁,保证同一时间仅能对同一共享对象进行操作。

在第三次实验的指导下,我使用了方法锁的方式来对共享对象加锁,所有的notifywait都在共享对象的方法中实现。在第一次作业中这样简单的设计是简介而有力的,但在第二、三次作业中,共享对象类型、方式增加——具体体现在第二次作业中新增电梯共享对象、第三次作业中新增向上返回的乘客共享对象,导致为了解决复杂的问题,需要对于多种方式进行独特的设计方法,这反而是有些不如在代码块中同步方便的。

2. 避免轮询!

我对于轮询的理解就是:存在这样一种情况,只要CPU不切换线程,你的某个线程就会在无意义的while循环。

无意义是指,如电梯运行中,对于仍有乘客在电梯中进行电梯运行的while循环来送乘客,便是有意义的;如分配器一直等input输入乘客,而不wait,便是无意义的。

事实上,我认为轮询是很容易debug的,对于一个线程,我们只需要查看是不是所有无意义情况下都会进入wait即可。

另外需要注意一点,如在第二次作业中,我的线程存在当楼层Floor没有横向电梯时,由电梯共享对象wait;当存在横线电梯而没有乘客可分配时,由乘客共享对象wait;所以每次唤醒时,请确定对正确的共享对象进行唤醒!

二、调度器设计

对于调度器设计,一方面是调度算法的选择,另一方面是确保线程关闭

1. 调度算法

我的调度算法并不优越。我采用了与指导书相同的分配方式,即对于楼层分配最优解,对于电梯循环分配。

如果使用生产者消费者模型,由电梯选择接收乘客,应该可以在算法上对性能进行优化。

2. 确保线程关闭

在前两次作业中,由于乘客分配是自顶而下分配的,所以对于线程关闭,也可以自顶而下反馈的。

但对于第三次作业,由于多了一份自下而上的反向传递乘客,所以原本的单纯根据上级完成线程、那么下方可以完成线程的方式不能保证线程的正确关闭了。

我采用的方法是:

  1. Input与Schedule的共享对象isEnd && isEmpty

  2. 对于每个共享(调度)的对象(包含三类:wait、elevator、back),都要isEmpty;

当二者都均满足时,从schedule自顶而下传递isEnd信号,逐级关闭线程。

这样子就有几个问题

1. 对于任何对象,改变容器时必须**先加后删**,否则会有一瞬间出现,二容器均不存在该对象的情况;
1. 对于schedule中,要新增当`input.isEnd && !allIsEmpyt`的判断;
1. 由于对于back类容器也要设为`isEnd`,但每次线程的wait是由wait类型容器控制唤醒,所以需要先对back类容器设`isEnd`,在对wait类型容器设置`isEnd`。

但事实上,在后续和同学讨论中,我们认为单例模式计数器是一个很优雅的判断结束方式。

三、线程协同框架

  • 第一次作业

第一次作业仅有固定的五座纵向电梯、仅有共享对象容器新增乘客,所以在结构上较为简单。

本次作业我尝试对于每一电梯采用自身的换乘表与策略,但由于是在换乘表(不同步)中完成乘客的上下电梯,所以产生了一些线程安全问题。

  • 第二次作业

第二次作业可以新增纵向电梯与横向电梯,但不能换乘。

在第一次作业的基础上,由于换乘表设计的缺陷,我进行了重构,删去了换乘表这一概念,直接将其内嵌入了电梯。并新增Building类与Floor类作为二级调度器对乘客、电梯进行分配。

  • 第三次作业

因为第二次作业写的时候,就猜到了第三次会需要换乘,所以在第二次作业的基础上可以进行逻辑上很轻松的迭代,只需要增加返回的共享对象、并对乘客行程进行记录即可,但对于判断线程结束的困难却多了许多。

UML协作图:

四、自己的bug

  1. 第一次作业中,我在弱侧阶段出现了轮询错误,但轮询的问题很好发现,只要对每个run函数进行分析即可;

  2. 除此之外,我出现最多的bug就是RTLE,在第一次作业中,由于自身书写的电梯运行策略存在问题,所以造成了其不如基准算法快的情况,在之后的作业中,我舍弃了对于算法的优化,基本使用look算法,并未出现此类问题;

  3. 另一种RTLE的原因,是不能实现线程结束。这在第三次作业中尤为明显,是有线程不安全导致的,因此只能通过不可复现的测试来逐渐改bug。

五、发现别人的bug

对于别人的bug,主要是对于可能存在的轮询与死锁进行特殊数据构造。

六、心得体会

unit2的对于多线程的学习,可以说是代码思想观念上的革新了)。从第一次作业磕磕绊绊不明白什么是轮询和思索,到逐渐根据实验代码思考原因,再到尽管对于上锁工具并没有多样性的掌握,但理解了对共享对象加锁,要在合适时候waitnotify,虽然强测成绩并不是很理想,但至少自己认为掌握了许多新的内容,抗压能力也越来越强了

posted @ 2022-05-03 20:28  iLoveFox  阅读(19)  评论(1编辑  收藏  举报