oo第二单元总结

oo第二单元总结

第一次作业和第三次作业为了优化,直接把调度策略整合到了电梯里,故不作讨论。

对于第二次作业,总体上采用了生产者-多消费者模型,各个消费者在各自的过桌子里拿产品,互不干扰,一定程度上将调度、分派和电梯运行分离了开来;但电梯仍是采用ALS的自律电梯,即能稍带则稍带,调度器的编写也是要针对ALS电梯来进行指令顺序调整的,没有完全实现调度策略的接口化。

同步块设置和锁的选择

由于一开始对其他锁不是很了解,故直接采用同步块和wait/notify的形式;

整体采用生产者-多消费者模型,即用共享队列来传递指令;同时共享对象中有end标志,结束线程时置位,从而逐级传递到各个电梯关闭;

同步块中一般是对共享队列进行查询等操作;Scheduler和Dispatcher执行时用到的电梯运行信息通过调用Elevator、Scheduler类里的同步方法得来,如int synchronized getLoad()就是取得负载;当然样得到的信息具有一定延迟,不能与电梯运行保持一致。

电梯之间有Building这个共享对象来保证执行指令的时候人已经到了相应楼层(没到就等待)。

image

调度器和分派器设计

Dispatcher设计了几种方式:

  • 默认模式:轮流循环分配,每次分固定数量的指令,直到把缓冲区内的指令全部分完
  • 负载均衡方式:根据负载的比例轮流循环分配
  • 同层出发分配:每次把同层出发且方向一致的的指令一同分配给一部电梯,再轮流循环分配下一种同层出发指令;这种方式主要是适应ALS策略,保证能尽可能多的稍带

而第三次作业加入了转乘策略:

  • 主观转乘:13层和1820层的给C电梯,奇数层的给B电梯,偶数层的如果跨层过大且只用转一次就把指令拆成两条并分别分派给AB电梯,电梯在没有人来时直接等待

Scheduler的设计:

  • 默认模式:按时间顺序直接放入
  • ALS:只把当前可稍带的放入,其他的先放入bufferQueue缓冲

交互主要为Scheduler与电梯、Dispatcher和Schedulers、Main与Dispatcher之间的交互:

  • Scheduler-Elevator:主要通过processQueue共享队列用同步块放置、修改指令队列进行交互;同时Scheduler要得到电梯的运行信息,要通过Elevator中的getDoorState等同步方法来获得,而Elevator修改时也是用相应的同步方法修改;Scheduler在电梯都没有执行完首指令且新指令无法放入时对wait信号量进行P操作,从而等侍;Elevator在执行完首指令后对wait信号量进行V操作,唤醒Scheduler。
  • Dispatcher-Schedulers:主要通过waitQueue共享队列同步块修改指令进行交互;同时有getLoad、getFloor等同步方法进行电梯状态的传递。
  • Main-Dispatcher:主要通过waitQueue共享队列和schedulers同步块进行交互;Main不断往waitQueue中放指令,Dispatcher每隔一段时间从waitQueue中取指令;schedulers为加电梯指令服务,由Main来执行,通过同步块保证写-读互斥。

架构分析

这个架构的主要缺点有:

  • 线程过多,导致电梯状态逆向传递时可能电梯已经运行到下一个状态了;其实只需电梯线程就可以,策略类可以由电梯线程调用,从而省去中间调度的线程。
  • 电梯的泛化性不强,电梯应该有run中直接调用策略类的方法,而不是让外部的策略方法去适配电梯的默认执行策略。

image

image

bug分析

在第二次作业中出现了隐藏的轮询bug,源于Scheduler类里的alsSchedule方法,原因是在所有bufferQueue(缓冲区)指令无法分配时(电梯未执行完首指令),没有让scheduler线程等待,从而导致scheduler不停尝试往processQueue里塞指令,发生轮询。

解决方法:写了一个信号量类wait,让elevator和scheduler共享wait,elevator执行完时对wait执行V操作,scheduler在所有指令无法分配时执行P操作进行等待。

hack策略

由于未写自动测评机,故采用人工构造和利用中、强测数据回归测试的策略;同时以visualvm辅助观察CPU利用率,以确定运行时有无出现轮询。

构造策略:

  • 多人在一层上,看有没有超容量
  • 实时构造请求:在电梯运行时构造不在电梯方向上的请求,尝试卡超时

本单元测试主要为多线程,故测试样例可以非静态,即可以实时根据程序的反馈构造对抗样例;同时测试时不仅要关注正确性,还要关注有无轮询出现,故需要实时调试工具的辅助。

心得体会

  • 线程流程最好短一些,可以防止信息的不同步
  • 最好要自己先写好需要用的锁,避免临时用同步块降低可读性
posted @ 2021-04-24 12:23  Kyle-Kirsten  阅读(58)  评论(0编辑  收藏  举报