BUAA-0.O第二单元总结

孙雯新-22373476 学生 2024-04-20 18:44:12

第五次作业

架构分析

  • UML类图

img

  • 时序图

img

构建流程

第一次的做法直接main生万物了(x

在main函数创建了输入线程、调度器、电梯和请求队列,其中请求队列分为总请求队列(输入线程和调度器之间的托盘),和分请求队列(电梯各自持有的待处理请求队列)

处理流程

InputThread读取输入放进总请求队列waitQueue,Dispatcher按照特定策略(这次是直接按照id)将总请求队列的请求分派给电梯的分请求队列,电梯处理自己请求队列里的请求

两种请求队列的设计

实现了两类请求队列,RequestQueue和RequestTable,其中的区别从名称也很容易看出来 x 前者是用ArrayList容器实现的队列,后者是为了方便按照楼层检索,用HashMap套HashSet实现的表

请求的分配用队列实现是因为符合先进先出的思想,而电梯请求的处理用HashMap实现是为了避免遍历,因为大多数时候都是按照楼层访问的

同步块和锁

将请求队列ReqeustQueue和RequestTable的所有方法加上synchronized修饰,使得共享资源的访问不会发生冲突

调度策略

按照id分发!

第六次作业

架构分析

  • UML类图

img

  • 时序图

img

新增需求

  • 实现电梯reset和reset期间静默
  • 重新处理reset电梯的请求

新增内容

  • ResetReq用于记录重置类别请求
  • DebugInfo用于输出调试信息
  • Count用于记录全局未完成的请求数目以及输入是否结束,用于判断是否结束线程

架构调整

  • 电梯线程与电梯分离,在电梯线程中管理电梯、策略类、待处理请求表和乘客目的地表
  • 在Dispatcher中管理电梯线程的创建和销毁

同步块和锁

  1. 用于实现wait-notify机制

    调度器和电梯在无需处理请求时均处于等待状态,需要在新请求加入时唤醒线程。对于总请求队列,设置Object phone;电梯设置Object elevatorPhone;重置请求设置 Object resetPhone作为共享资源,来限制特定语句块的访问

  2. 用于实现reset期间电梯功能的沉默

    通过synchronized(resetPhone)使得”电梯reset“和”电梯请求分配“ 两个行为互斥(这个愚蠢的实现在后面出了大大的bug,且看后面bug分析)

调度策略

由于学习多线程锁的使用和debug花了太多时间,只写了一个简单的条件优先分配策略

在和请求同向的、未满员的所有电梯里面,==优先选择最近的==,其次选择人少的;

如果不存在符合该条件的电梯,则直接选择人最少的

(这个策略在互测的时候被大家锤爆了ORZ)

第七次作业

架构分析

  • UML类图

img

  • 时序图

img

新增需求

  • 实现重置电梯为双轿厢电梯

新增内容

  • 开始时创建12个电梯,其中6部不运行;为elevator新增属性isRunning用于标识电梯是否运行或存在
  • 在ResetRequest中新增属性isDoubleCarReset,区分两类reset请求;新增属性transferFloor,若为第一类reset指令缺省值为-1
  • 修改reset方法,分resetA、resetB和normalReset三种情况讨论
  • 修改调度方法

同步块和锁

OS大法好,信号量救我狗命

由于在这种架构设计中,并不存在井道,因此12部电梯其实是相互独立的,用于识别两个电梯是否在同一的井道的标志只有id,如果id<6,该电梯的”另一半“就是id+6的电梯

那么这两部电梯的同步就是一个问题,主要涉及两点:

1. 如何写Barrier让电梯一起开跑

当电梯被reset为双轿厢电梯时,原电梯reset,伙伴电梯start,如何保证他们俩一起开始跑(也就是一起出reset)

在这里用了OS里面学到的信号量实现barrier机制:

电梯和伙伴电梯共享两个信号量sem1和sem2,初始值都为0,在原电梯reset的结尾加上

sem1.release();
        try {
            sem2.acquire();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

伙伴电梯reset的结尾加上

sem2.release();
        try {
            sem1.acquire();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }      

两部电梯就会一起离开reset方法啦

2. 如何保证不撞

  • 及时让位:如果终点超出楼层范围,或者等于换乘层,在换乘层将旅客送出后,反向,并远离换乘层移动一层
  • 进前检测:上下层电梯之间,维护一个容量为6的标签数组ArrayList<Flag> transferOccupied,为false时才能进入换乘层,进入之后置为true,离开时再置为false并notify;如果为true则需要等待
    • 具体实现:修改move函数,如果是双轿厢电梯,在curFloor++之前检测即将到达的是否为换乘层

调度策略

在上次的优先分配策略上进行了改动(加入了随机性),防止把所有请求塞给一个电梯导致的超时(被hack怕了),大概如下

if (satisfiedIds.size() != 0) { // 有满足需求(达到一定优先级别)的电梯
            blabla……
        } else { // 没有满足需求的电梯,在可到达的电梯中选择一个
            return elevatorIds.get((int)(Math.random() * (elevatorIds.size() - 1)) + 1);
        }

然后是针对双轿厢电梯的部分:

如何进行调度

如何实现:双轿厢电梯只会被分配特定楼层范围内的请求?

写一个Elevator.inFloorRange(PersonRequest request)函数,加入分配的条件判断

关于双轿厢电梯

到达换乘层之后干什么:

  1. 放出抵达目的地的乘客
  2. 放出需要换乘的旅客
  3. 接收需要上车的乘客
  4. 光速离开

bug记录

调度器被硬控1.2s(hw6)

为了达成reset时不能receive的目的,简单的给调度器Dispatcher中为该电梯添加receive的代码上了锁;也就是说,如果电梯在reset过程中被分配了请求,调度器会一直等待直到该电梯reset完毕

设计太愚蠢了()这样会导致调度器直接被==硬控1.2s==,如果有新的reset请求进来就没办法及时处理了

果然临界区和锁的使用是一门大学问啊

解决方法:新增共享对象线程安全处理 isReseting,并加入buffer机制,reset过程中给电梯加入的请求会被加入buffer,等到结束统一输出receive

双轿厢电梯在reset缝隙被塞入了无法完成的请求(hw7)

由于buffer机制,电梯在reset过程中可以接受请求,放在buffer里面,等到reset结束再输出receive;但是由于双轿厢电梯reset时会更改maxFloor和minFloor,存在这样一种情况:reset开始了但是尚未修改参数,此时调度器获取了reset前电梯的数据并将请求分配给该电梯,但是这个请求的楼层reset后的电梯无法到达。

可能的解决方式:1. 如果是第二类reset,在reset成功后再次将buffer中的请求丢回主请求队列重新分配,考虑到第二类reset最多出现六次,这种方法应该也不会造成太大的性能影响;2. reset成功后检查buffer中的请求,将无法完成的请求丢回主请求队列; 3. 第二类reset过程中电梯完全不接受请求

综合考虑后,在这里采取第二种方式进行修复

buffer在倒入电梯的过程中被加入的新请求(hw7)

循环过程中修改了ArrayList,向buffer中加入了新请求,导致java.util.ArrayList$Itr.checkForComodification

解决方式:调整了出Reset的位置,避免在清空buffer的时候向buffer中新增请求

心得体会

线程安全

  • 如果能考虑周全一次成型就最好了(x 感觉经常缝缝补补又出新bug

  • 由于感觉synchronized够用就偷懒没换读写锁QAQ,现在感觉如果hw6就换读写锁,会对线程安全的理解更加深刻一些吧

  • 信号量救我狗命

层次化设计

处于可拓展性考虑,在hw5就写了相对清晰的架构(比如在hw5其实没什么用的Dispatcher),后面基本没有大的改动

别的感想

多线程的bug真的好难de(爆哭

以及特别特别感谢一起讨论问题、无私帮助我的老师们(比心

下一届可能的新活

  • 加个楼梯
    • 楼梯限制:两层之间限行6人
  • 新增乘客类型
    • 分为old和young,走楼梯一层时间分别为4s和2s
  • 双轿厢电梯不限制换乘楼层
...全文
61 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

301

社区成员

发帖
与我相关
我的任务
社区描述
2023年北航面向对象设计与构造
学习 高校
社区管理员
  • YannaZhang
  • CajZella
  • C_ecelia
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧