BUAA OO UNIT2 目的选层电梯单元总结

BUAA OO UNIT2 目的选层电梯 单元总结

同步块&锁

hw5

在等待队列Qu上的锁上,输入线程和调度线程成为一对生产-消费关系。而调度线程和电梯在Rlist上的生产-消费关系则由Rlist自身的同步方法保证线程安全。电梯对象的锁在本次作业是没有使用必要的,但为了后续作业考虑,还是使用了电梯对象锁。ElvMotor运行时会被创建为一个电梯的守护线程,负责处理开关门、上下楼的时序问题,内部所有方法都是synchronized方法,电梯通过暴露的cmd方法操作该线程。

Qu Rlist Elv ElvMotor
IN run()
Trans Close(), tr(), run()
Rlist add(), done(), qry(), poll()
Elv setClsd(), add(), done(), redir(),port(), run() redir(), port(), wk(), run()
ElvMotor flr(), gate(), up(), dn(), open(), close(), cmd(), run()

hw6

输入线程和调度器的关系与hw5相同,但由于采用了共享等待队列的架构,Qu上还增加了属于电梯线程的临界区。为防止调度器同时调度多个电梯造成混乱,调度器内部launch等方法被设计为synchronized。电梯内部的诸多方法也被设计为synchronized,以防止调度器修改电梯参数时发生混乱。ElvMotor守护线程与hw5相同。

Qu Trans Elv ElvMotor
IN run()
Trans close(), launch(), nalloc(), run() Newelv(), launch(), run() launch()
Elv porti(), run() wtf(), dir(), launch(), tp(), dis(), done(), ori(),wk(), run()
ElvMotor flr(), gate(), cmd(), up(), dn(), run()

hw7

输入线程不再直接操作等待队列,而是通过调用Base提供的方法修改等待队列,同步块更集中。将ElvMotor改为Elv的private类,不再作为守护线程独立存在。

Qu Elv Elv.Motor
Base req(), alloc() alloc()
Elv release() port() go(), open(), close()

调度器&线程交互

hw5

调度器仅负责把请求从主等待队列转储到电梯等待队列中,直接用synchronized块解决即可。

hw6

调度器负责把电梯“发射”至目标楼层,目标楼层可以是出现请求的楼层,也可以是约定好当没有可分配请求时应去往的停泊楼层。

调度器有主动入口和被动入口:新增请求时输入线程激活调度器,使用主动入口;电梯轿厢为空时调用调度方法,使用被动入口。

hw7

调度器每隔200ms扫描一遍等待队列,刷新每个请求分配的电梯号码,刷新每个电梯的目标楼层。依次trylock所有电梯,若成功则signal()。除sleep(200)外,调度器永不休眠,因而也不需要被唤醒。调度器给每个电梯设置目标楼层时赋值语句是原子语句,不需要加锁。

平衡&可拓展性

hw5

电梯自身调度是魔改的莫队算法,希望利用请求出现的局部性,优先在一段小区间里往返送人。人少的时候效果极差。类图中Rlist类是莫队实现的主要基础。在此基础上增加电梯非常容易,只要继承电梯类,并重写与停靠楼层、运行速度相关的方法即可,调度器也只需改为转储时向不同电梯写入请求即可。

性能:失败;可拓展性:良好。

diagram5

main5sequence5

hw6

使用共享等待队列,Rlist被弱化为仅包含判断方向是否相同、比较距离远近的静态方法。共享队列 + 调度器分配目标楼层 的架构兼具抢人和分配两种思路的优势,性能优秀。但共享队列带来了一些线程安全问题,其解决较复杂。由于调度时认为各电梯之间没有属性上的差异,因此增加电梯种类可能导致调度器出现较大改动。

性能:优秀;可拓展性:一般。

diagram6

main6sequence6

hw7

共享队列plus。调度器每隔200ms刷新一次,重新分配请求,设置每部电梯的目标楼层。每个请求增加权限部分,可以只允许指定电梯载客,考虑了每部电梯之间属性差异。通过删除调度器唤醒电梯以外的所有唤醒操作、删除与等待队列或电梯线程无关的所有临界区,成功杜绝了线程安全问题。实现了简单的换乘,但总体性能似乎没有不换乘好。

性能:较优秀;可拓展性:尚可。

diagram7 main7

sequence7

bug

hw5

  • 没有发现bug

hw6

  • 没有互测中发现的bug

  • 强测第9个点运行过慢的"bug"

    • 特征:贪心算法在极端情况下失效

      Class CogC ev(G) iv(G) v(G)
      Trans.nearq() 5 4 2 5
    • 位置:Trans(调度器)类,nearq方法

    • 修复:qu.size()>=6则改成裸的抢人

  • 本地以1/30的频率稳定复现调度器唤醒电梯时被阻塞,导致电梯请求调度时发生死锁的bug。

    • 特征:在需要系统原语的地方使用了两步判定

      Class CogC ev(G) iv(G) v(G)
      Trans.run() 22 4 10 11
    • 位置:Trans(调度器)类,run方法

    • 修复:改用trylock()

hw7

  • print过于靠后的bug

    • 特征:代码长度7,圈复杂度1

      Class CogC Ev(G) iv(G) v(G)
      Elv.Stop.release() 1 1 2 2
    • 位置:Elv(电梯类)->Stop子类,release方法

    • 修复:print语句移到该方法第一行

  • 分配时发生数组越界的bug

    • 特征:未考虑参数在执行过程中被其他线程修改的情况

      Class CogC ev(G) iv(G) v(G)
      Trans.run() 39 8 13 16
    • 位置:Base(调度器)类,alloc方法

    • 修复:cnt改为tmp.length

分析别人bug

  • 测试策略
    • 黑盒测试,一次运行30个子进程
    • 有效性:模拟评测机运行情况,并发现了强测未发现bug
  • 线程安全相关
    • 所有测试数据均为随机生成,实际上由于线程安全问题的不确定性,我不认为手动构造有明显效果
    • 同时运行多个测试进程,增大了线程安全问题出现的概率
  • 与第一单元的差异
    • 第一单元hack重心在于正确性判定,第二单元重心在于线程安全问题。
    • 第一单元数据构造策略显著影响hack效率,需要用心构造高强度数据。
    • 第二单元如何运行多进程,如何判定CTLE和RTLE,如何杀死TLE的死锁进程显著影响hack效率。

心得

共享队列的idea

相比于在两级队列之间做分配和重配,不如只做一个共享的队列来得方便。然而,这显然会导致一些线程安全问题。

如何解决呢?我选择减少线程间的通信,并且禁止多个对象在同一个锁上调用wait()方法。这样已经解决了绝大部分线程安全问题,余下的问题是:调度器尝试激活电梯时电梯会小概率自行激活,导致调度器被阻塞,后续电梯notify调度器,请求调度时会发生死锁。

造成这个问题的原因是调度器已判断电梯处于WAITING状态,又尚未激活电梯时,电梯自行唤醒,使调度器被阻塞。这时将if判断放进同步块只会增大阻塞发生概率,不能解决问题。于是我在本单元第三次作业改用了tryLock()方法,解决了这个问题。

IMG_0157IMG_0158

调度算法实现

只有调度器发射某个电梯后,该电梯才允许载客。电梯在被发射后运行look算法,不断捎带有权限捎带的乘客,直到轿厢为空,而调度器又未给该电梯分配新的目标楼层。这时电梯进入空闲状态,不再载客。

本单元第二次作业调度器:贪心地给电梯分配相比其他电梯都更近的乘客所在楼层,如果不存在,则分配一个预先算好的停泊楼层(每20/总电梯数量 个楼层设一个停泊楼层)。这个策略在真随机数据下性能良好,但在特殊构造的数据下容易被卡。一个临时补丁是:如果等待队列里人数>6则退化回暴力抢人。

IMG_0159IMG_BDD641B0C356-1IMG_0161

第三次作业改进

改用trylock()之后,我令调度器每200ms刷新一次等待队列,重新分配请求。这样,调度器不再需要被输入线程或电梯线程激活,降低了架构复杂度。电梯的目标楼层每200ms刷新一次,应该能收获更好的性能。同时,调度器分配请求时,优先从最小到达时间最长的请求开始分配,避免了贪心算法在极端数据下失效的问题。

IMG_0160IMG_0162

第三次作业中还出现了电梯与调度器不同步的问题,电梯运行一层的时间会略大于k*200ms,导致需要多等待200ms才能被激活,结果就是所有电梯上升/下降一层的时间都增加了0.2s。解决方法是尽量让电梯不休眠,不再每运行一层就等待调度,而是直到轿厢为空才进入休眠。这样就大大降低了以上情况出现的几率。

IMG_0164
posted @ 2021-04-23 19:41  fallqs  阅读(127)  评论(2编辑  收藏  举报