第二单元第一次作业

多线程设计策略

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

为了这么做输入线程与电梯线程有一共享变量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. PTA 统计二叉树结点个数

    6-1 统计二叉树结点个数 (10 分)   本题要求实现一个函数,可统计二叉树的结点个数. 函数接口定义: int NodeCount ( BiTree T); T是二叉树树根指针,函数NodeCo ...

  2. 【Django笔记0】-Django项目创建,settings设置,运行

    Django项目创建,settings设置,运行 1,项目创建 ​ 通过pip下载Django以后,在cmd中cd到想要创建项目的路径,之后输入: django-admin startproject ...

  3. Spring Boot 轻量替代框架 Solon 1.3.15 发布

    Solon 是一个微型的Java开发框架.项目从2018年启动以来,参考过大量前人作品:历时两年,4000多次的commit:内核保持0.1m的身材,超高的跑分,良好的使用体验.支持:RPC.REST ...

  4. 极简实用的Asp.NetCore模块化框架新增CMS模块

    简介 关于这个框架的背景,在前面我已经交代过了.不清楚的可以查看这个链接 极简实用的Asp.NetCore模块化框架决定免费开源了 在最近一段时间内,对这个框架新增了以下功能: 1.新增了CMS模块, ...

  5. mysql基础自学

    1.1基础查询 语法:select 查询列表 from 表名;注意:1.查询列表可以是:表中的字段.常量值.表达式.函数2.查询的结果是一个虚拟表格 完整的写法是:先声明使用哪个库,再写SQL语 如果 ...

  6. SpringCloudAlibaba—微服务概念及SpringCloudAlibaba介绍

    目录 1.1 系统架构演变 1.1.1 单体应用架构 1.1.2垂直应用架构 1.1.3 分布式架构 1.1.4 SOA架构 1.1.5 微服务架构 1.2 微服务架构介绍 1.2.1 微服务架构的常 ...

  7. 【PHP】用了这么久的Laravel框架,你分析过核心架构了没

    Laravel最初的设计是为了面向MVC架构的,它可以满足如事件处理.用户身份验证等各种需求.另外它还有一个由管理数据库强力支持,用于管理模块化和可扩展性代码的软件包管理器. Laravel以其简洁. ...

  8. Windows系统搭建ELK日志收集服务器

    一.ELK是什么?ELK是由Elasticsearch.Logstash.Kibana这3个软件的首字母缩写. Elasticsearch是一个分布式搜索分析引擎,稳定.可水平扩展.易于管理是它的主要 ...

  9. [解决] Assertion `srcIndex < srcSelectDimSize` failed.

    在finetune Chinese GPT2的时候遇到如上错误,错误原因index越界,原始代码中给定的输入长度是1024,但是我使用模型可接受的输入长度是512,把输入长度都改为512,错误解决

  10. Leedcode算法专题训练(双指针)

    算法思想 双指针 167. 两数之和 II - 输入有序数组 双指针的典型用法 如果两个指针指向元素的和 sum == target,那么得到要求的结果: 如果 sum > target,移动较 ...