第二单元第一次作业

多线程设计策略

第一次作业的想法是设计三个线程:输入线程,调度器线程以及电梯线程。输入线程获取请求并发送给调度器线程;调度器线程通过查询电梯线程的状态(等待、停靠以及移动),并综合已有的请求为电梯线程分配目标;电梯线程根据分配到的目标进行移动,并进行上下乘客操作。

为了这么做输入线程与电梯线程有一共享变量requestQueue用以保存请求,调度器线程与电梯线程有一共享变量taskQueue用来保存电梯的移动目标。这种设计的初衷是让不同线程尽量只干自己该干的事,即输入线程负责请求的输入,调度器线程负责请求的调度,电梯线程负责模拟电梯运动以及人员出入。这么做的好处一方面在于各个线程的职责都十分明确,另一方面在于调度器便于实现更加灵活的调度策略。但这么做的问题在于调度器访问得到的电梯线程状态与电梯线程实时状态并不是同步的,所以在调度器类以及电梯类中都需要加入较多语句来保证调度器能够及时地为电梯更新目标,以及电梯能够正确处理目标。同时另一个问题就是调度器主动分配目标的做法在多部电梯时需要考虑的情形较多,处理起来比较复杂。

度量分析

方法复杂度(其中较复杂的几个)

类复杂度

类图

协作图

本次作业的复杂度主要集中在AlsElevator类以及ElevatorController类中,前者主要与收集电梯运动状态,以及控制运动有关,后者主要与根据不同情况分配目标有关,算是在保证不同类有有不同分工的同时分散了复杂度。同时预留了一个Elevator接口,本来以未之后的作业会加入不同类型的电梯,所以预留接口一边迭代,但由于没有考虑清楚作业的扩展方向,所以最终都没有使用上这个接口。

BUG相关

本次作业在本地测试时一开始遇到的bug主要是线程的退出问题,原先的做法是电梯在无目标时,则睡眠以等待调控器分配目标,但最初由于处理不当导致电梯线程对最终的终止信号响应失败,最终通过增加额外判断,解决了这一问题。

在互测方面,还是以自动测试为主,由于多线程细节方面有很多线程安全的问题,所以自动测试的随机性能取得一定的效果。

心得体会

作为第一次多线程作业,这次作业的起点对我来说还是比较高的。且由于吃了设计缺陷的亏,使得自己在保证线程同步方面耗费了很多精力,也算是告诫自己要先考虑好设计在进行程序的实现吧。

第二单元第二次作业

多线程设计策略

由于这次作业需要完成多部电梯的设计,所以为了降低调度器与电梯之间的耦合度,讲任务分配方案改为电梯主动从调度器获取目标。每个电梯维护自身的目标队列,当目标队列为空则睡眠等待调度器唤醒。调度器负责在有新的请求到来时或者请求未被完全处理完但有电梯在睡眠时向电梯发送通知。当调度器唤醒了多部电梯时,电梯间竞争获取请求。

通过这种处理,较第一次作业来说极大地减少了调度器线程与电梯线程之间的耦合度,并因此大大降低了保证线程间同步的难度。

度量分析

方法复杂度

类复杂度

类图

协作图

从复杂度来看,这次作业相比与第一次作业很明显的就是复杂度集中到了Elevator类中,这是因为Elevator类既需要完成电梯运行的模拟还需要为处理如何获取请求以及请求应该如何安排的问题。从具体的方法复杂度也可以看出Elevator类中关于如何将得到的请求安排到目标队列的方法占据了复杂度的很大一部分。虽然改变了控制策略,但整个程序在大体上也延续了第一次作业中的结构。

BUG相关

在做第二次作业时本地遇到的bug是没有分电梯是否满人来进行请求的处理,出现的情形是电梯已经满人无法继续接受请求,但安排任务的函数没有考虑到这一点而不断为电梯安排这个无法处理的请求导致的。

在互测阶段由于对大多数人来说,这次作业相较于上次作业的只是简单的增加了几部电梯,并且在第一次作业中已经积累了一定的经验,所以这次的尽管也是采用自动测试的模式,但挂了相当长一段时间都没有成功找到他人的bug。

心得体会

虽然大部分人这次作业都延续了上一次作业的风格,但由于我这一次改变了整个控制的策略,就导致需要在Elevator类以及ElevatorController类中做较多变动。但也算是及时止损吧,如果按照上一次作业的思路,那这次作业调度器需要考虑问题复杂度对于我自己来说应该是非常大的。虽然最后程序的复杂度被集中到了Elevator类中,但整体实现起来的难度却相较于上一次作业有所下降。

第二单元第三次作业

多线程设计策略

本次作业对上一次策略进行了较大的延续,但也做了几处更新。第一个更新是对换乘的支持,我才用了一种比较妥协的换乘策略,即自己实现了一个请求类,并将所有请求都分为两步:第一步是能进入哪种电梯,第二步是能从哪种电梯中出来,然后根据进入电梯的情况,有这个自定义的请求类自己生成出电梯的楼层。这样做的话每个请求的运载就被分为两种情形:如果第一次进入的电梯可以直接送达就直接让这个电梯送达,如果不能则请求类的目的楼层为某一个中转楼层以便第二次运输就可以到达终点。第二个更新是电梯的运行方式,之前是以目标队列中下一个目标来进行移动,而这次更新为将目标队列进行升序排列,然后始终往队列两端中离当前楼层较近的一段移动,这种方法较前一种方法可以较少很多细节方面的实现,所以性能可能有所损失,但是起来简单很多。最后一个更新是调度器在给电梯通知的同时会多加一个可选的目的层以帮助电梯减少决策的复杂度。

度量分析

方法复杂度

类复杂度

类图

协作图

对于这次作业新增的换乘请求,我的想法是想模仿人自己处理换乘操作,所以新建了一个MyRequest类,用来处理与换乘相关的操作。由于新建的这个类分担了很多很多有关目标处理的操作,同时也对电梯运行的策略进行了简化,所以在这次作业中几个类相较于上一次作业复杂度都有了一定程度的降低,特别是Elevator类,这个类基本回归了第一次作业的角色,主要处理电梯移动的模拟。除了新增的MyRequest类以外,其他几个类之间的相互关系跟第二次作业相近。

BUG相关

本次作业在一开始在本地测试发现了这样一个bug:由于我电梯的设计是当不再有请求,同时请求队列为空时会开始向下传递终止信号,等电梯运送完这次任务就结束程序,但有时候电梯内部可能有需要换乘的人员,这就会导致人员未被送完程序就结束了。

另一个bug是在互测阶段产生的,最后发现是一个死锁的bug:电梯与调度器之间有一个互相唤醒的关系存在,当电梯状态更新,或是有新请求到来时,调度器会被唤醒;当调度器发现有未处理请求且有电梯在休眠时,调度器会唤醒电梯。但这样一个关系存在一个问题,就是当电梯正好要去睡眠前,调度器检查发现无可调度电梯于是进入睡眠,但下一刻电梯恰好都去睡眠了,于是就会出现互相等待对方的死锁局面,最终通过设置wait时间上限来向这一bug妥协。

心得体会以及总结

这次作业通过MyRequest类的增加,我认为在一定程度上平衡了不同类的复杂度,同时也较上一次作业对类之间的职责有了清晰一点的划分。但我这三次作业中都没考虑过的一个问题就是调度器是否需要单独设置成一个进程的问题,现在考虑来看由于调度器的操作场景完全是在外界状态有更新时(包括有新的请求、电梯状态更新等)才需要进行操作,所以完全可以不需要设置成一个进程,直接让输入进程与Elevator进程把调度器当作一个共享资源来操作即可,同时这样做还有一个好处就是可以不在考虑电梯线程与调度器线程之间的同步问题,也能在一定程度上使得实现更简洁也更安全。

对于程序的扩展性,考虑了临时删除电梯以及乘客中途更换目的的情况。临时删除电梯可以通过将电梯从电梯集中删去,并通过endSignal信号让电梯在运送玩这次任务后就结束来实现。对于乘客临时更换目的地,由于MyRequest类就是一个模仿乘客行为的类,所以通过更改MyRequest对象的一些属性就可以简单地实现乘客的临时换乘。

北航OO(2020)第二单元博客作业的更多相关文章

  1. OO第四单元博客作业

    OO第四单元博客作业 BUAA_1706_HugeGun 目录 第四单元作业架构设计 四个单元架构设计及OO方法理解 四个单元测试理解与实践演进 课程收获 一点建议 第四单元作业架构设计 ### 第十 ...

  2. oo第三单元博客作业

    JML语言理论基础 Java建模语言(Java Modeling Language,JML)是一种进行详细设计的符号语言,他鼓励你用一种全新的方式来看待Java的类和方法.JML是一种行为接口规格语言 ...

  3. OO第二次博客作业—17373247

    OO第二次博客作业 零.写在前面 OO第二单元宣告结束,在这个单元里自己算是真正对面向对象编程产生了比较深刻的理解,也认识到了一个合理的架构为编程带来的极大的便利. (挂三次评测分数 看出得分接近等差 ...

  4. OO第二次博客作业——电梯调度

    OO第二次博客作业——电梯调度 前言 最近三周,OO课程进入多线程学习阶段,主要通过三次电梯调度作业来学习.从单部电梯的傻瓜式调度到有性能要求的调度到多部电梯的调度,难度逐渐提升,对同学们的要求逐渐变 ...

  5. OO第4次博客作业

    OO第4次博客作业 一.第4单元设计 第四单元主要围绕UML图的结构进行JAVA代码编写,对JAVA的层次结构进行更多的认识.个人认为编程操作在实质上与上一章的PathContainer有许多的相同之 ...

  6. BUAA 2020 软件工程 个人博客作业

    BUAA 2020 软件工程 个人博客作业 Author: 17373051 郭骏 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 个人博客作业 ...

  7. [BUAA OO]第三次博客作业

    OO第三次博客作业 1. 规格化设计的发展 我认为,规格化设计主要源自于软件设计的两次危机.第一次是由于大量存在的goto语句,让当时被广泛应用的面向过程式的编程语言臃肿不堪,在逻辑性上与工程规模上鱼 ...

  8. OO第三次博客作业——规格

    OO第三次博客作业——规格 一.调研结果: 规格的历史: 引自博文链接:http://blog.sina.com.cn/s/blog_473d5bba010001x9.html 传统科学的特点是发现世 ...

  9. OO第四次博客作业!

    oo第四次博客作业 一.测试与正确性论证比较 测试只是单方面片面的证明对于当前的输入程序是正确的,测试只能证明程序有错误,不能说明程序是对的. 正确性论证是程序达到预期目的的一般性陈述,是通过规范化的 ...

随机推荐

  1. ECMAScript 2017(ES8)新特性简介

    目录 简介 Async函数 共享内存和原子操作 Object的新方法 String的新方法 逗号可以添加到函数的参数列表后面了 简介 ES8是ECMA协会在2017年6月发行的一个版本,因为是ECMA ...

  2. kmp&字典树 模板

    kmp: const int maxn=1e5+5; char s[maxn],p[maxn]; int nex[maxn]; int KmpSearch(char* s, char* p) { in ...

  3. 攻防世界 reverse debug

    debug  XCTF 3rd-GCTF-2017 .net程序,这里我用的dnspy,当然.net Reflector也很好用. 查看程序,发现是明文比较,下断,debug,完成. flag{967 ...

  4. Vulkan移植GpuImage(二)Harris角点检测与导向滤波

    Harris角点检测 UI还是用的上次扣像的,只有前后置可以用,别的没有效果,只看实现就好. 相应源码 在实现之前,我先重新整理编译glsl的生成工具,如Harris角点检测中间计算过程需要针对rgb ...

  5. CVE-2021-21402 Jellyfin任意文件读取

    CVE-2021-21402 Jellyfin任意文件读取 漏洞简介 jellyfin 是一个自由的软件媒体系统,用于控制和管理媒体和流媒体.它是 emby 和 plex 的替代品,它通过多个应用程序 ...

  6. SqlServer存储过程应用二:分页查询数据并动态拼接where条件

    前言 开发中查询功能是贯穿全文的,我们来盘一盘使用存储过程分页查询,并且支持动态拼接where条件. 划重点:支持动态拼接where条件 对存储过程的使用有疑问的同学去[SqlServer存储过程的创 ...

  7. Leedcode算法专题训练(搜索)

    BFS 广度优先搜索一层一层地进行遍历,每层遍历都是以上一层遍历的结果作为起点,遍历一个距离能访问到的所有节点.需要注意的是,遍历过的节点不能再次被遍历. 第一层: 0 -> {6,2,1,5} ...

  8. Dapr | 云原生的抽象与实现

    引言 Dapr 是微软主导的云原生开源项目,2019年10月首次发布,到今年2月正式发布 V1.0 版本.在不到一年半的时间内,github star 数达到了 1.2 万,超过同期的 kuberne ...

  9. Mybatis3源码笔记(一)环境搭建

    1. 源码下载 地址:https://github.com/mybatis/mybatis-3.git. 国内访问有时确实有点慢,像我就直接先fork.然后从git上同步到国内的gitte上,然后在i ...

  10. 如何解压从UK biobank下载下来的tsv.bgz文件?

    今天碰到一个问题,就是从UK biobank下载下来的gwas result file是filename.tsv.bgz格式.这东西需要解压才能阅历,可是用zip或者rar都是搞不定,网上搜了一圈,说 ...