OO第二单元总结

OO第二单元总结

一、作业介绍

(一)作业背景及迭代

​ 本单元的核心是模拟多线程实时电梯系统,总共有A~E五栋楼,各拥有10层。要求设计一个电梯调度系统,采用一定的调度策略,用以实时响应可以在任意时间发出的电梯搭乘请求,具体需要模拟实现电梯的上下行、开关门以及进出人。

  • 三次作业介绍
    • 第一次作业:五座楼各有一个属性确定的纵向电梯,初始时停在一层。题目要求系统能响应仅为同一座楼的搭乘请求。
    • 第二次作业:新增了横向电梯的概念,能在A~E座间以环形顺/逆时针方向运动。同时新增了可添加纵向/横向电梯的ADD指令,要求系统能响应仅为同一座楼或同一层楼的搭乘请求,需注意横向搭乘请求只会出现于有横向电梯的楼层。
    • 第三次作业: 电梯可通过ADD指令定制运行时间和载客数量,同时横向电梯增加了可达性的设置,即横向电梯仅在规定的楼座可以开门。要求系统能够响应任意的搭乘请求,即要求实现转乘功能,乘客可能乘坐不止一部电梯来达到目的地。

(二)训练目的

​ 通过这一单元的学习,初步掌握多线程概念及其设计方式,了解常见的多线程设计模式、不同线程间的交互方式,并同时学习线程安全知识和锻炼解决线程安全问题的能力。

二、作业分析

(一)同步块与锁

​ 为什么需要同步块与锁?在多线程程序中,如若不同线程无限制地访问同一共享资源,便可能会由于操作被打断等情况导致线程安全问题,因此我们需要用到锁来设置同步块,以保证在某一线程访问该同步块时获取到锁,避免被其他线程干扰,访问先后有序,从而保证线程的安全。要保证线程安全,我们要认识到原子操作这一概念,类似于量子的概念,即该块的操作应被看作为一个整体,不应在执行过程中被其他线程而中断,这样保证了功能的正确实现,而锁与同步块的作用就是将块中的处理语句包装成原子操作,形成一个整体。

​ 在笔者的架构种中,仿造了实验代码设计了一个请求队列共享类RequestQueue,用synchronized锁对该队列的addRequest、getRequest方法加锁设置了同步块,保证了请求投喂线程和请求处理线程对该共享队列访问的线程安全。该类在架构中实现了输入线程InputThread和调度器Schedule间的待分配队列waitQueue,以及调度器Schedule和电梯Elevator间的任务队列requestQueue

​ 除此之外,在hw6和hw7中,出现了添加电梯的ADD指令,使得任务队列requestQueue会动态增加,因此笔者设计了共享类QueueList,根据读取队列操作远多于添加新队列操作,笔者尝试采用了读写锁ReentrantReadWriteLock,为添加新队列操作加上了写锁writeLock,为读取队列操作加上了读锁readLock,既保证了多个队列管理的线程安全,又在定程度上提升了不同线程的访问效率。

(二)调度器设计

  • 笔者的作业主要采用了生产者-消费者模式,大体上线程分为三种:InputThread输入线程-Schedule调度线程-Elevator处理线程,三种线程依托于前文说到的请求队列共享类RequestQueue实现线程交互。

    • InputThread输入线程:从输入中读取指令,一方面实现电梯添加的ADD指令,另一方面将所以搭乘指令添加到与Schedule线程共享的等待分配的请求队列waitQueue中。

    • Schedule调度线程:笔者采用了单调度器的架构,即有且仅有的一个全局调度器Schedule不断从waitQueue获取待分配的请求,通过调度器策略,将这些请求发放到各个电梯自己的请求队列requestQueue中去,从而实现调度。除此之外,在hw7中,Schedule线程还承担了为需换乘指令分解乘坐步骤,为其分段分配电梯的角色。

    • Elevator处理线程:该线程功能纯粹,即不断从自己的requestQueue获取发配给自己的请求,对请求做出响应,模拟实现上下楼、开关门和进出人。

  • 调度器策略分析与设计

    • hw5中各座楼仅且仅有自己的一部电梯,因此调度器Schedule只需判断各请求所在的楼,将其加入各座楼相应的请求队列即可。
    • hw6中出现了横纵电梯以及多电梯竞争的情况,在实现了区分横向请求与纵向请求后,笔者采用了平均分配方式,即基准策略中第一个乘客给第一部电梯,第二个乘客给第二部电梯……如此类推下去的方式。
    • hw7的主要重难点在于请求可能需要换乘,需要有调度器来实现该乘客的搭乘策略,从而成功到达目的地。
      • 换乘策略:题目背景中规定了初始在一层中有一部可达所有座的横向电梯,因此保证了任何请求一定可以在不大于三次的乘坐电梯后到达目的地。基于此,笔者设计了一种依托于请求本身信息、最多乘坐一次横向电梯的转乘调度策略。在官方包原有PersonRequest拥有的域基础上,笔者为每个Request添加了五个域curBuilding、curFloor、dirBuilding、dirFloor、M,表示该请求的乘客当前所在位置、下一步搭乘一次电梯所能到达的短期目的地以及调度器为他找寻的中转楼层M。
        • 调度逻辑如图
      • 除此之外,在了解到hw6中许多同学使用自由竞争获得了高分后,笔者在hw7中也抛弃了平均策略而采用了自由竞争,即同一层楼或同一座楼的电梯共享同一个请求队列,而非一部电梯一个队列,使得电梯可以自己去“抢请求”,但没想到这一改动与横向电梯可达性结合后出现了意料之外的bug,这一点会在后面bug分析中详细解释。

(三)架构分析与总结

  • 三次作业类图及其迭代
    • hw5:基础架构,仿照了实验代码,核心为输入、调度、处理三大线程
    • hw6:相较于hw5,新增了QueueList类用于同一管理多个电梯的请求队列,调度器给电梯发放任务的过程由原来的直接投放到对应电梯变为:先由QueueList获取相应电梯的请求队列,再将请求插入该请求队列中。另外,按照作业要求,给InputThread新增了创建新电梯线程的能力。
    • hw7:为实现前文所说的hw7调度器设计,自己新增了原官方包中PersonRequest类的升级版Req类,另外给ELevator开放了将到达目的地的请求重新加入waitQueue的权利。除以上两点,其余设计均大体相同。
  • 未来拓展能力:在上述架构中,各部分结构的功能划分鲜明,生产者与消费者角色有着明显区分,程序的可拓展性强。例如若给纵向电梯加入可达性限定,只需给电梯加上纵向可达性Info即可;在比如一个乘客可能需要依次到达多个地方,只需修改Req的存储结构以及升级调度器Schedule的调度模式即可。
  • UML协作图:具体介绍见前文调度器设计

三、bug分析

(一)自己的bug

笔者的bug全出现在第七次作业中,都是由于横向电梯可达性这一设定导致。

  • ①只用了一个int变量switchInfo来记录该层的可达性,有新电梯加入时通过或运算来更新该层的switchInfo,这样导致或运算合并后,本应需要搭乘两次横向电梯才可到达的情况显现成了只需搭乘一次,又由于笔者采用的架构是最多乘坐一次横向电梯,因此可能会导致给某一请求设置了不合理的中转楼层,导致该请求在进入中转楼层的等待队列后,无法被处理,最终导致任务未完成,程序亦无法正常结束。修复方法是新建一个容器用于存放不同的switchInfo,在查询时遍历该容器即可。
  • ②在原本的程序中,如若请求队列为空电梯载客为空则调用wait释放CPU资源,但在横向电梯有可达性的设定下,加之hw7中笔者改用了多个电梯共享一个请求队列的自由竞争,出现了请求队列不为空,但横向电梯却无法获取到可响应的请求的情况。笔者没有考虑到这一点,这导致了该横向电梯会连续不断地向请求队列中尝试获取一个可响应的请求,但总是无功而返,从而使得CPU不断被占用,最终导致了CTLE的错误出现。对此的修正方法是,若该电梯未能获取到可响应的请求且目前电梯未载人,则wait释放资源,避免占用。

(二)互测

第二单元中笔者仍旧使用了手搓数据的互测方式,针对某一可能出现bug的特点进行数据构造。

  • hw5整体来说较为基础,可能产生的bug不对,笔者主要针对的同学们未能留意到的输出时间戳需保证时间顺序这一要求,在同一时间点给入大量请求,以此检验是否会出现时间戳不递增的bug。
  • hw6出错的可能性亦不大,主要是检验横向电梯的功能正确性, 给如大量的横向搭乘请求,从而检验其能否正确完成任务。
  • hw7较为复杂,笔者大体针对两个方面。一是就横向电梯的可达性限制进行测试,检查是否有不可达导致的上下人错误以及陷入无法结束的错误;二是就转乘进行测试,构造一般三段式转乘以及可能优化后使用更多次转乘的数据,检验其正确性。

相较于第一单元的碰运气测试,第二单元的数据构造更具有针对性,从结果来看,这样的策略算是较为成功。

四、心得体会

​ 通过这个单元对多线程的学习,我深刻体会到了多线程间交互、合理分配系统资源的巧妙与优美,了解到许多的设计思路与模式,同时也遇到了本单元最核心的线程安全问题,为此没有少掉头发,但在成功保证了自身程序的线程安全性后的成就感也是无以伦比的。除此之外,我还深刻认识到了正确性检验的重要性,一开始拥有优美简洁的设计固然重要,但在程序完成后的测试环节亦必不可少,编程中的手误、思维上的漏洞,这些bug往往难以直接观察代码发现,通过测试发现bug后逆向寻因,才效率最高,也更大程度上保证了程序的正确性。

​ 总体来说,这个单元的学习令我大开眼界,受益良多,学习到了以往许多未曾接触到的新知识,OO越学越发现其意义之非凡,接下来的OO学习我亦要继续努力。感谢老师和助教们的辛勤付出!

posted @ 2022-05-03 14:37  kingimtk  阅读(48)  评论(2编辑  收藏  举报