OO第二单元电梯总结

(1)总结分析三次作业中同步块的设置和锁的选择,并分析锁与同步块中处理语句直接的关系

第五次作业

  • 第五次作业只有两个线程,涉及到的线程安全问题的类有总请求队列(requestQueue)和电梯任务队列(waitQueue)。

    • 通过官方包读入请求到总请求队列,加入请求时要锁总请求队列

    • 从总请求队列中读取请求到电梯任务队列,删掉被分配的请求时要锁总请求队列,加入请求到电梯任务队列时要锁电梯任务队列

    • 电梯到达目标楼层出人,删除请求时要锁电梯任务队列

    • 调度策略访问空的电梯的任务队列时要锁电梯的任务队列(在此处wait交锁)

    • 判断电梯线程是否结束时要锁电梯任务队列(此处对电梯任务队列和总请求队列做了一定的关联)

  • 被锁的总请求队列和任务队列与同步块的关系有以下情况:

    • 对总请求队列或电梯任务队列进行添加或删除操作

    • 此时需要准确知道电梯任务队列状态

第六次作业

  • 第六次作业与第五次作业相比在线程上没有很多修改,仅增加了调度器线程承担托盘职能,涉及到线程安全问题的类仍然只有总请求队列(requestQueue)和电梯任务队列集合(taskQueues)。

    • 将第五次作业中的电梯任务队列改为被访问的特定电梯任务队列

    • 需要对TimeableOutput加锁避免出现输出顺序与时间戳顺序不一致的错误

  • 被锁的总请求队列和任务队列与同步块的关系有以下情况:

    • 对总请求队列或某一电梯任务队列进行添加或删除操作

    • 此时需要准确知道某一电梯任务队列状态

    • TimeableOutput被调用时更新时间戳

第七次作业

  • 第七次作业在第六次作业的三个线程的基础上进行修改,同类电梯竞争同一任务队列,其余没有做出修改,涉及到线程安全问题的类有总请求队列(requestQueue)、电梯任务队列集合(taskQueues)和乘客请求保存容器(personReqSave)。

    • 将第六次作业中的电梯任务队列改为所属类别的电梯任务队列

    • 从总请求队列中调度到

  • 被锁的总请求队列和任务队列与同步块的关系有以下情况:

    • 对总请求队列或该所属类别的电梯任务队列或乘客请求保存容器进行添加或删除操作

    • 此时需要准确知道所属类别的电梯任务队列状态

    • TimeableOutput被调用时更新时间戳

(2)总结分析三次作业中的调度器设计,并分析调度器如何与程序中的线程进行交互

第五次作业

没有调度器,输入线程与电梯线程直接进行交互。

第六次作业

  • 将总请求队列中的乘客请求(PersonRequest)随机分配到电梯的任务队列中

  • 按照总请求队列中的电梯请求(ElevatorRequest)启动电梯线程

第七次作业

  • 基于dijkstra算法生成静态换乘表

  • 将总请求队列中的请求(PersonRequest)查表转换为新的请求流(PersonReqUpd),并将其按照首次应当乘坐电梯类型分配到对应类别的电梯序列中

  • 按照总请求队列中的电梯请求(ElevatorRequest)启动电梯线程

  • 作为电梯的属性被电梯线程调用处理未完成的换乘请求,即将没有结束的换乘请求按照下一次应当乘坐的电梯类型分配到对应类别的电梯任务队列中

(3)从功能设计与性能设计的平衡方面,分析和总结自己第三次作业架构设计的可扩展性

  • UML类图

  • UML协作图(sequence diagram)

  • 架构设计可扩展性分析

    • 架构设计

      • 本次作业并没有过分追求性能而损害程序架构,但是为了将未完成的请求重新放回电梯任务队列,选择将调度器作为电梯的属性,导致两者有部分耦合

    • 可扩展性

      • 本次作业封装了dijkstra算法,更新生成有向图的方法(graph.init())即可完成最优换乘策略的分析

      • 本次作业实现了策略模式和状态模式,在增加新的模式或新的状态、更改旧状态时并不需要改变顶层的设计

      • 本次作业由于电梯类型较少,没有实现电梯接口或抽象类,出现新类型的电梯并不能通过重写方法得到

      • 本次作业在控制电梯行为时,由于懒惰,仅仅在第一般电梯的基础上增加传入了电梯类型参数进行讨论,非常不符合面向对象的思想

(4)分析自己程序的bug

  • 线程安全bug

    • 第六次作业电梯不能正常结束:在处理CPU轮询后引入了电梯不能正常结束的bug,电梯在调度策略中做了访问的任务队列为空就做wait()处理且电梯状态变化与电梯结束、电梯非空两个判断条件的关系不是if else,所以如果唤醒它的是电梯结束,那么会停留在这个状态不结束

    • 第七次作业电梯不能正常结束:同样由于处理CPU轮询后引起,personReqUpdSave用于记录每个请求的换乘是否已经结束(输入结束不能作为调度器分配结束的标志),如果查询personReqUpdSave不能得到调度器分配线程结束的结果,即有请求并没有执行完成所有换乘,就会调用wait()等待,且仅仅在电梯线程将未完成所有换乘的请求重新加入到所属类别的电梯任务队列后唤醒,那么当不需要换乘的请求为最后一条请求时,personReqUpdSave最终不会被唤醒,调度器分配结束标志始终为false,电梯无法正常结束

  • 其他本地bug

    • 第五次作业

      • 调度策略:由于没有考虑清楚电梯状态变化的捎带策略和电梯策略类的策略之间的关系和电梯目标楼层参数(targetFloor)的意义,导致程序逻辑混乱,最终做了很多讨论以诡异的姿态跑了起来

      • CPU轮询:在没有请求的时候,电梯在waitState和arriveState之间不断变化且不断更新targetFloor,需要在更新targetFloor的方法中增加wait(),而由于使用了状态模式,更新targetFloor的方法在第三层(调用handle(),调用randomStrategy,调用getTarget()),顶层看起来固然漂亮,但是debug很困难

    • 第六次作业

      • 调度策略:虽然重构了调度策略的部分代码,但是电梯状态变化的捎带策略和电梯策略类的策略互相影响的关系并没有解决,bug修复疯狂打补丁,直到第七次作业改成了ALS调度

    • 第七次作业

      • dijsktra算法:开始对dijskra理解不够透彻,后来get得到引用不能赋值导致核心条件并没有修改

      • 电梯开门出人更新请求逻辑:由于最开始只会用removeIf,遍历过程中不能删除,由于同一任务队列被同类型所有电梯且电梯状态不断改变,上一刻遍历得出存在可稍带请求需要开门,下一刻开门却不一定能竞争到请求,最终使用迭代器实现了边遍历边删除的方法

      • 换乘细节:请求每poll出一个楼层,fromFloor和toFloor的值会被更新,此时判断是否到达目标楼层的条件变为targetFloor和fromFloor是否相等(此处依赖实现细节),以及换乘的电梯类型在何处更新,要进行细致的考虑

      • 电梯结束条件判断错误:开始误把电梯总请求队列为空作为调度器分配结束的标志,后续bug见线程安全bug

  • 公测强测互测bug

    • 第六次作业强测150s输入的数据rtle:调度策略有错误导致部分捎带没有实现

  • 心得体会

    • 不好的架构极大地增加了设计和debug的难度

      • 例如第五次作业在实现MorningStrategy时,调用getNearestReq()这一函数而不是直接return 1,用来规避CPU轮询,不清楚targetFloor的含义导致这里必须采用很tricky的方法,极大增加了设计难度

      • 例如第七次作业在建立无向图时,节点数组0号代表1层,1号代表2层以此类推,这样的架构极大地增加了debug的复杂程度

(5)分析自己发现别人程序bug所采用的策略

  • 测试策略

    • 模块化测试

      • 例如第六次作业将调度器的随机分配策略改为全部分给0号电梯来测试0号电梯的运行

    • 手动构造数据

      • 例如手动构造输入时间间隔较长的数据测试是否会出现CPU轮询(由于采用了状态模式可以直接printf)

    • 阅读调度策略代码

  • 线程安全测试策略

    • 手动构造数据

      • 例如手动构造输入时间间隔较长的数据测试是否由于修改轮询引入wait()后程序不能正常结束

    • 梳理锁和同步块的逻辑

  • 与第一单元测试策略的差异

    • 黑箱测试方面,评测机搭建存在困难

    • 白箱测试方面,多线程和电梯实现细节问题过多,思考难度较高

(6) 心得体会

  • 线程安全

    • 使用线程安全类是良好的习惯

    • 对照现有模式(如生产者消费者模式)设计是良好的习惯

  • 层次化设计

    • 确定和区分各部分职能是良好的习惯

    • 封装顶层保留部分接口是良好的习惯

  • 三次作业一直在重构,多线程的bug常写常新。虽然每次都会后悔为什么不沿用上一次还能使用的架构,虽然每次过了公测都真情实感地再也不想看代码一眼,虽然电梯已经结束了还是像得了电梯PTSD一样永远能发现关键词,我还是选择去写我想的电梯。

  • 博观而约取,厚积而薄发。共勉。

posted @ 2021-04-26 00:03  wyq1217  阅读(116)  评论(2)    收藏  举报