zoukankan      html  css  js  c++  java
  • OO第二单元总结

    前言

      我认为第二单元的三次作业在实现上较第一单元容易,电梯的调度算法并不复杂。但多线程的许多不易察觉甚至无法复现的潜在问题就要求写代码时要在设计结构层面避免线程安全问题的出现。所幸本轮三次作业线程之间的协同竞争关系较易把握,一种设计模式便足以应对。

    设计策略

      三次作业均遵照如下模式设计:

      在调度器(Dispatcher)中设置缓冲区存储待响应指令,将调度器其传入输入(InputHandler)和电梯(Elevator)参与线程状态控制。输入和电梯竞争调度器中的资源,这样共享资源保护只需通过同步调度器中的方法即可实现。

      三次作业中电梯调度均采用ALS算法,其优势在于将电梯的一次执行视为对不断变化的主指令(主指令在电梯到达某层时更新)的获取和响应的过程。如此,电梯的一个执行周期便可简化为获得主请求getMainRequest() + 响应主请求respondMainRequest()两个过程,十分有利于实现。两方法具体内容(捎带,请求的获得、响应原则)根据作业要求做出修改。代码复用性好。

      按照ALS算法的要求,电梯中存放正在响应的主请求及捎带请求集合。当电梯为空时,从调度器的待响应队列中选出主请求并前往,在每行进一层后从新选择主请求;当电梯非空时,总以电梯内到达楼层距离电梯当前楼层最近的请求作为主请求响应,对于捎带请求的响应也是通过其在特定条件下升级为主请求后响应主请求实现的。也即是说,电梯每次完成的一定是主请求,这样能有效减少错误的发生。

    基于度量分析程序结构

    第一次作业

    类图

      本次作业最大的问题是当输入未结束而待执行请求队列为空时电梯会不断循环判断请求队列是否为空及输入是否结束,浪费cpu资源。应通过wait,notify让出cpu。后续作业采用了这种方式。

    第二次作业

    类图

    第三次作业

    类图


     方法度量(截取高复杂度)


      本次作业中,除每个电梯的待响应队列外还在调度器中添加了暂存二段请求的缓冲区来寄存被拆分请求的后半段。每当一个请求响应完毕后,都判断能否将缓冲区中的某请求添加到电梯待响应队列中。本次作业基于这个机制做了两点优化:一为当同时刻出现许多请求时按照A-B-C-A-B-C-……的顺序将其添加到电梯各自的待响应队列中。二为当电梯的响应队列为空但发现有能响应的二段指令时会去响应二段指令,这一过程会在出现能直接响应的请求后被打断以保证响应二段指令不会严重影响对能直接完成的请求的响应。

      由于这些优化,添加(拆分)指令及电梯run方法的分支变多,没有想出能有效降低分支数的写法。

    bug分析

      第一次作业的一组数据中出现了不响应到来较晚的请求的bug,疑似是因轮询导致cpu占用超时导致进程被提前杀死。

      第三次作业有两个bug。一为默认了中转站一定在两楼层之间导致FROM-2-TO-3这类相邻楼层需中转的请求得不到响应。二为当电梯达到二段指令起始层时会忙等,直到出现可以直接完成的请求,导致cpu_time_limit_exceed。这些bug反映出对边界情况考虑不周到的问题。

      当不存在二段指令暂存队列时,电梯线程的退出条件即为1.输入结束,2.待响应队列为空。由于加入了暂存二段指令的集合,退出条件有所改变,当二段指令暂存区不为空时也不能退出。这些空队列的情况隐含数组越界的隐患,因此需要保证从调度器的任何队列中获取请求时队列一定非空,后续处理才能安全进行。改正后电梯运行逻辑如下:

    while (true) {
      if (elevator's to-respond queue is empty) {
          if (second-gear request buffer is empty) {
              if (input steam is over)
                  kill_thread();
              else
                  wait();
         } else
              respond_buffer_request();
      } else
          get_and_respond_main_request();

    }

    bug策略

      主要针对判断分支较多的地方(包括捎带,是否会超载,指令拆分,结束条件等)设计测试样例,并构造了耗时较长的请求序列测试电梯运行效率。但并未hack到很多bug。第一单元由于结果带入x的值后是唯一的,可以通过对拍器找bug,而本次作业则只能通过判断电梯是否符合原则地在规定时间内完成了所有请求实现自动化测试,难度较高。

    心得体会

      保证线程安全的核心在于对可能发生冲突的共享资源的识别和保护。线程之间的高效协作有赖于执行顺序的同步控制。这些都需要在写码之前先想清楚。设计模式上,电梯的作业考察了简单的生产者消费者的设计模式,还需积累更多多线程设计模式以处理其他种类问题。

  • 相关阅读:
    (二分查找 拓展) leetcode 69. Sqrt(x)
    (二分查找 拓展) leetcode 162. Find Peak Element && lintcode 75. Find Peak Element
    (链表) lintcode 219. Insert Node in Sorted Linked List
    (二分查找 拓展) leetcode 34. Find First and Last Position of Element in Sorted Array && lintcode 61. Search for a Range
    (最短路 Floyd) P2910 [USACO08OPEN]寻宝之路Clear And Present Danger 洛谷
    (字符串 数组 递归 双指针) leetcode 344. Reverse String
    (二叉树 DFS 递归) leetcode 112. Path Sum
    (二叉树 DFS 递归) leetcode 101. Symmetric Tree
    (二叉树 递归) leetcode 144. Binary Tree Preorder Traversal
    (二叉树 递归 DFS) leetcode 100. Same Tree
  • 原文地址:https://www.cnblogs.com/blueshift/p/10763961.html
Copyright © 2011-2022 走看看