BUAA_OO Unit 2 多线程电梯调度

§2 多线程电梯调度

C1 设计结构

0)三次作业的设计结构基本不变,第二次尝试引入了集中调度器,等待队列私有化。看守和调度器共享一个缓冲池,性能效果不佳,遂删除。第三次由于换乘需要引入虚拟楼层组。

由于没有复杂继承结构和对象管理,我选择不使用UML类图。

1)线程类:

  • 电梯 Elevator:负责运送乘客
    • 主要私有资源:
      • 搭乘队列
    • 主要共享资源:
      • 全局等待队列
  • 看守 Guard:负责IO处理,读入并处理请求(新增电梯或者将乘客放入等待队列
    • 主要共享资源:
      • 全局等待队列

2)资源类:

  • 楼层组:Arraylist<Arraylist<Person>> Queues 可以方便地进行检索。楼层组会有一个量表示组内人数

  • 等待队列:持有两个楼层组,一个是虚拟组,由于存放换乘时产生的虚拟目标,一个是实际组。有一系列查询方法,如waitAtForward,waitToForward用于电梯查询是否有合适目标

  • 搭乘队列:一个楼层组,是各个电梯私有的

  • 乘客:含有最终目标和用户id。有一个accept(int currentfloor, string elevatortype)用于查询用户是否接受某电梯(比如电梯根本送不到目标楼层就拒绝)。因为电梯拉取乘客和等待队列查询合适对象都会使用这一方法,所以放在乘客内更好。也符合对对象建模的思想

3)工具类:

  • 楼层映射:用于建立楼层数和索引数映射
  • 换乘表:用于调度时查询乘客若乘坐该电梯将选择的楼层

C2 运行流程

1)长的亚批的UML序列图对于说明运行流程其实没有太大作用,这里我还是选择流程图,结合设计模式进行描述

2)主要的设计模式:

  • Worker Thread 模式 : WaitQueue作为托盘存储乘客。电梯作为Worker。而Guard可以视为Host以及Client。作为Host,Guard会在接受增加电梯时启动新的电梯线程。作为Client,Guard将乘客加入等待队列。电梯在等待队列中,寻找自己能够处理的对象,并且有时也放回一些产品(换乘)
  • 工厂模式:ElevatorFactory负责生产不同类型的电梯线程,本次实验我没有将不同类电梯视为不同子类,而是采取参数组合的方式,只要修改电梯参数,就可以生产不同类型的电梯。
  • 状态模式:电梯内部的运行采取状态模式建模。关于状态模式,可以参考我在第六次作业讨论区的一篇帖子
  • 信号灯:电梯线程结束采取信号灯方式

3)运行流程图

C3 关于多线程互斥机制

1)

C4程序运行结构分析

C5 电梯调度

0)这个算法很大程度上其实是受到LPX学长说他瞎写的算法的启发做的。

1)调度器设置

  • 集中式调度:中央调度器将请求分配到各个电梯独立的等待队列。对具体的某个电梯,如何处理分配到的任务可以由其局部调度器自行解决。
    • 难点:合理分配使得各个电梯以最高效率承载。随时间推移,电梯间负载差异增大,需要对未服务对象进行再分配,均衡负载
    • 优点:如果不做再分配逻辑,实现起来异常简单
  • 分布式调度:不存在中央调度器,电梯共享一个等待队列,独立进行调度
    • 难点:避免多个电梯同时服务一个目标,而实际只需要一个电梯,故需要目标互斥
    • 优点:由于共享一个等待队列,不需要进行负载均衡处理。
  • 第三次作业中我使用的是分布式调度,负载均衡对性能的影响确实非常大。同时,电梯每到一层都会进行一次调度。

3)调度算法

  • LOOK算法:在前进方向上没有新请求时折返。该算法的原理是尽量使得行程重叠,从而减少电梯运行距离。

    (举例而言,1-9,2-10两段行程中,2-9是重叠的)

    • 优点稳定可靠,用户被服务的最长等待时间在一个最大折返时间内。且在多梯调度下,电梯分布相对均匀,用户请求也更早被处理。
  • SSTF算法:寻找最近请求。原理是贪心。

    • 优点:理论上,SSTF算法有最短的平均响应时间(但等待时间不意味着服务时间最短)

    • 缺点:第三次作业由于加入了服务等待时间这一请求,基础款的贪心算法难以保持原有性能。

      (举例而言,电梯内有3个人希望前进,此时身后一层来了一名乘客,电梯会折返而导致3名乘客多等了3 * 1.2s)

  • 第一次作业中,我使用的是魔改版LOOK算法(能不让乘客下电梯就不让下。举例而言,某乘客到达5层,但是电梯发现6层和1层都有请求,未来一定会再次经过5层,所以不会把人放下去)

  • 第二次作业中,我使用的是SSTF算法+集中式调度(无均衡负载的集中式调度害了我的性能分QAQ)

  • 第三次作业中,使用的是局部优化的LOOK算法

4)局部优化:

  • 服务对象互斥
    • 理想的处理方式:提供一个电梯目标面板,电梯每次调度决定服务楼层都发布到该面板后进行移动。其它电梯调度时,查看电梯目标面板是否与自己选定的目标一致。若一致,比较查看是否自己更加适合(更近、容量足够),然后再发布自己的目标。原先那个电梯移动一层后返回,会再进行一次调度,这时它会发现有其它电梯已经发布了相同目标。它进行相同的操作,查看自己是否有继续服务的必要,再发布目标
    • 残酷的现实:我的时间不够充裕,没有实现这个好方法。所以我的电梯还是会前往同一楼层服务乘客。但是我做了一些优化,每个电梯进入等待队列取乘客的临界区时,检查是否有开门的必要,如若没有(说明先进入的电梯已经把人取走),则不开门,重新进入调度状态。这样做也仅是减少了开门时间,但是效果上和上面的处理方式相近
  • 逆行乘客捎带:由于电梯有容量限制,电梯捎带时应当考虑是否将逆行方向的乘客捎带
    • 理想的处理方式:电梯总是把逆行方向的乘客带上,在遇到前方有前进请求而容量不足时,将一个逆行方向的乘客换下来。
    • 残酷的现实:我只考虑电梯运行前方无请求时才会拉取逆行乘客。
  • 虚拟目标:指乘客换乘时,在换乘层添加一个虚拟的自己。例如from 2-pass 1-to 3,乘客会在1层设置一个虚拟目标。这样C电梯可以提前到1层等候,从而协调工作。
    • 电梯只在没有可服务非虚拟对象时才会服务虚拟目标。一来可以简化程序逻辑,二来避免不必要的等待
    • 但是这样做使得虚拟目标在电梯系统相对空闲时才开始起效(比如刚刚开始和接近结束时)
  • 减少A梯在两端往返:A梯经常往返两端会造成损失,所以应当在15层和3层检查两端请求是否已经处理完毕。

5)换乘策略:

  • 静态换乘策略:电梯事先决定好换乘方案,按照指定行程处理。

    动态换乘策略:将电梯的实时位置纳入考虑。对于SSTF算法的电梯,这种处理收效甚微

  • 换乘策略的各段行程分配可分集中式和分布式,集中式将各个行程段分配给各类电梯负责,分布式由任意电梯负责

  • 本次作业中,我使用的是分布式分配,静态换乘方式。

    • 换乘表的生成: table[from][to]

      • 首先使用邻接矩阵检查到每两个点之间总是有长度小于2的可达路径

      • 若可直达 table[from][to] = to

      • 若需要一次换乘 table[from][to] = pass

        pass 是使得 |pass - from| + |to - pass|最小的换乘点

      • 得到的表还需要进一步微调

    • 为A型,B型,C型各安排一张表。

      tableA生成的条件:可由A梯直达,或者A梯送到一个楼层,该楼层可由B或C梯送达最终层

    • 乘客根据前来的电梯类型对自己的请求进行拆分,查表,若为-1,表示不接受该电梯,拒绝进入。否则,加入电梯内对应的到达楼层队列。

  • 举例而言

    2-3的乘客,查AC表,不可达。查B表,应当加入B梯楼层1队列。随后从1层出来,查AB表,不可达,查C表,直达。

    1-5的乘客,若B先来,直达,进入B梯5层队列。若C先来,直达,进入C梯5层队列。A梯不会来,因为它在调度查找下一目标时可以查表提前发现该乘客自己无法服务该乘客。

不知道写点啥。贴张没啥用的换乘表(表中是按楼层索引号组织的,0就是-1层)好了。另外,这个表改一改,其实就可以直接改成集中式分配,不同类型电梯搭载不同乘客。

    static {
        tableA = new int[][]{
            {-1, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,17,18,19,20,21,22},
            { 0,-1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,17,18,19,20,21,22},
            { 0, 1,-1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,17,18,19,20,21,22},
            { 0, 1, 2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,17,18,19,20,21,22},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            { 0, 1, 2, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,18,19,20,21,22},
            { 0, 1, 2, 3,17,17,17,17,17,17,17,17,17,17,17,17,17,17,-1,19,20,21,22},
            { 0, 1, 2, 3,17,17,17,17,17,17,17,17,17,17,17,17,17,17,18,-1,20,21,22},
            { 0, 1, 2, 3,17,17,17,17,17,17,17,17,17,17,17,17,17,17,18,19,-1,21,22},
            { 0, 1, 2, 3,17,17,17,17,17,17,17,17,17,17,17,17,17,17,18,19,20,-1,22},
            { 0, 1, 2, 3,17,17,17,17,17,17,17,17,17,17,17,17,17,17,18,19,20,21,-1}
        };
        tablemap.put(1, tableA);
        tableB = new int[][]{
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1, 2, 3, 4, 3, 6, 7, 8, 9,10,11,12,13,14,15,16,17,17,17,17,17,17},
            { 1, 1,-1, 3, 4, 3, 6, 7, 8, 9,10,11,12,13,14,15,16,17,17,17,17,17,17},
            { 1, 1, 2,-1, 4,-1, 6, 7, 8, 9,10,11,12,13,14,15,16,17,17,17,17,17,17},
            { 1, 1, 2, 3,-1, 3, 6, 7, 8, 9,10,11,12,13,14,15,16,17,17,17,17,17,17},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            { 1, 1, 2, 3, 4, 7,-1, 7, 8, 9,10,11,12,13,14,15,16,17,17,17,17,17,17},
            { 1, 1, 2, 3, 4,-1, 6,-1, 8, 9,10,11,12,13,14,15,16,17,17,17,17,17,17},
            { 1, 1, 2, 3, 4, 7, 6, 7,-1, 9,10,11,12,13,14,15,16,17,17,17,17,17,17},
            { 1, 1, 2, 3, 4, 7, 6, 7, 8,-1,10,11,12,13,14,15,16,17,17,17,17,17,17},
            { 1, 1, 2, 3, 4, 7, 6, 7, 8, 9,-1,11,12,13,14,15,16,17,17,17,17,17,17},
            { 1, 1, 2, 3, 4, 7, 6, 7, 8, 9,10,-1,12,13,14,15,16,17,17,17,17,17,17},
            { 1, 1, 2, 3, 4, 7, 6, 7, 8, 9,10,11,-1,13,14,15,16,17,17,17,17,17,17},
            { 1, 1, 2, 3, 4, 7, 6, 7, 8, 9,10,11,12,-1,14,15,16,17,17,17,17,17,17},
            { 1, 1, 2, 3, 4, 7, 6, 7, 8, 9,10,11,12,13,-1,15,16,17,17,17,17,17,17},
            { 1, 1, 2, 3, 4, 7, 6, 7, 8, 9,10,11,12,13,14,-1,16,17,17,17,17,17,17},
            { 1, 1, 2, 3, 4, 7, 6, 7, 8, 9,10,11,12,13,14,15,-1,17,17,17,17,17,17},
            { 1, 1, 2, 3, 4, 7, 6, 7, 8, 9,10,11,12,13,14,15,16,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}
        };
        tablemap.put(2, tableB);
        tableC = new int[][]{
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1, 5, 7, 7, 7, 9, 9,11,11,13,13,15,15,17,17,17,17,17,17},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            { 3, 3, 3, 3, 3,-1, 7, 7, 7, 9, 9,11,11,13,13,15,15,17,17,17,17,17,17},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            { 3, 3, 3, 3, 3, 5,-1,-1,-1, 9, 9,11,11,13,13,15,15,17,17,17,17,17,17},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            { 3, 3, 3, 3, 3, 5, 7, 7,-1,-1,-1,11,11,13,13,15,15,17,17,17,17,17,17},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            { 3, 3, 3, 3, 3, 5, 7, 7, 7, 9,-1,-1,-1,13,13,15,15,17,17,17,17,17,17},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            { 3, 3, 3, 3, 3, 5, 7, 7, 9, 9,11,11,-1,-1,-1,15,15,17,17,17,17,17,17},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            { 3, 3, 3, 3, 3, 5, 7, 7, 9, 9,11,11,11,13,-1,-1,-1,17,17,17,17,17,17},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            { 3, 3, 3, 3, 3, 5, 7, 7, 9, 9,11,11,11,13,13,15,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
            {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}
        };
        tablemap.put(3, tableC);
    }

总体来说,效果不错,8个点100分。同时欢迎大家关注公众号 15号放映室 ,我有不少设计元素是从往期推送中获取的。

猜你喜欢

转载自www.cnblogs.com/TwoBeNo-0/p/12705012.html