BUAA面向对象第二单元作业总结

三次作业总结主要分为以下几个部分的内容:

  • 多线程协同和控制
  • 基于度量的程序结构分析
  • 程序bug检验
  • 心得体会

多线程协同和控制

  第一次作业为傻瓜式先来先服务电梯调度,而且不考虑捎带优化。所以设计非常简单,只需要满足相关的线程同步避免轮询即可。

  具体的设计为两个线程: (1) 电梯线程 (2)输入线程

    线程互斥:两个线程竞争的资源区为 一个公共的队列,所以对该队列的访问需要进行加锁,

    线程同步:当没有需求时,电梯线程等待;当输入添加到等待队列时,电梯线程被唤醒。

  第一次作业为多线程的基本应用,为保证扩展性,不增加优化部分。

  第二次作业为可稍带的先来先服务电梯调度。相比第一次只是增加了可稍带部分,所以只需要增加捎带算法即可。

  同样的捎带算法是电梯每层停靠时自主检测完成的,所以融入到第一次作业的互斥区访问即可。

  第三次作业增加到了三个电梯线程。

  设计之初,不考虑电梯间的协作优化,只考虑可达性问题,将需要换乘的部分分为两段,分别给不同电梯调度,通过计算可达矩阵完成电梯分配。

  每个需求到来时将其立即分配给某个电梯,则转化为第二次作业的部分。

  每个电梯拥有一个自己的需求等待队列,独立调度。完成某项需求第一部分时,判断是否需要换乘,如需换乘,添加到另一个电梯的队列中。

  所以这形成了一个哲学家就餐问题,再电梯换乘时,一个需求需要从一个队列删除再添加到另一个队列。

  为了破除这种锁嵌套获取的问题,采取了缓存flush策略,即,将所有需要换乘的需求缓存下来,释放掉删除需求队列的锁后, 再获取添加需求队列的锁,将所有需求添加进去。

  这样保证了任意线程再同一时刻只会有一把锁,不会产生死锁问题。

基于度量的程序结构分析

作业类图

  第一二次作业类图是第三次作业类图的真子集所以,下面只给出第三次作业的类图进行分析。

  从下图中可以看出,本单元类图结构十分清晰, transfor 类为计算转移矩阵的类,其被Input Model 和Elevator 调用。

  InputModel 和 ElevatorObj 是主要的两个线程,分别为输入调度类和电梯类,两者被主类所创建。

  InputModel 类中方法非常少,只有调度和输入,电梯把所有行为封装到自己内部,耦合性非常好。

  综上,本单元类的设计采取了简洁高效的策略,类之间分工明确,结构简单。

  

UML 时序图

    下图为UML 时许图,三次作业均采用了两线程模式,输入模块同时也是调度器,电梯换乘可以被视作新需求的到达来。

    调度器将需求分配给某个电梯之后由电梯自行运转满足需求。

第一次作业

   类的相关统计数据

  LOCM表示耦合程度,期望其值低;FANIN表示内聚程度,所以期望FANIN的值要高。

  

   方法度量 

  LOC表示代码行数,CC表示循环,PC表示方法的参数

  可以看出大部分方法行数较短,几个主要的方法行数比较长,这是比较符合常规的。

  

第二次作业

  类的相关统计数据

  

     方法度量 

第三次作业

  类的相关数据统计

 

  代码异味

  

  通过分析看出在out 函数中使用了大量的神仙数(没有明确标明意义的常数),这个在以后的作业中需要修正。

  以及比较复杂的条件和比较复杂的方法,这些都是需要进一步重构的方法。

  方法度量 

 

程序bug检验

  对于程序中的bug检测,首先要立足于对多线程的深刻理解,在本三次作业中,虽然没有互测环节,但是我们还是尽量对自己的程序尽可能多的测试。

  Bug检验是一个由简单到复杂的过程:1.分析线程关系-> 2.线程是否公共资源互斥-> 3.线程是否可以进行同步 ->4.捎带效率和可达性检查

  脚本生成数据检查  

  1. 使用python脚本,随机生成需求,并再随机的时间按批次投入。
  2. 按照电梯运行规则进行检查输出结果 和运行时间

  检查出的错误主要有:

      (1)线程synchronize 区域粒度不够细,出现带锁睡觉

      (2)线程之间synchronize 嵌套,出现哲学家就餐问题

  在测试中出现的其他问题,对于最后结束添加一个NULL进入队列,所以需要对NULL的需求特判

  本地执行和采用命令行执行效果不一样,所以要经过命令行执行的检验。

  bug 主要处于线程访问公共资源区的位置Elevator 的Transfor 函数区,所以对公共资源访问和电梯同步要仔细设计检查。

  第一单元错误主要出现在顺序逻辑和某些输入WF情况下,对于多线程重点在于公共资源的互斥访问和线程的同步上。

 总结

    通过本单元的作业基本了解了面向对象多线程基础思想,进一步积累了一些重构的工程经验。

    线程安全上讲,尽可能地不要让一个线程同时获取两把锁,这样极有可能造成线程死锁。

    在线程同步方面,wait 和 notify 都是基于公共资源区的,这样从设计上可以避免死锁,同时也比较符合人的思维规范。

    在设计代码的时候首先分析出公共资源区,然后对公共资源区的访问代码范围尽可能缩小粒度,避免出现重叠现象。

    应该能够比较迅速的识别出经典的线程模式,如生产者消费者模型,哲学家就餐问题,发布订阅模式等,这些都有助于我们快速构建多线程代码。

猜你喜欢

转载自www.cnblogs.com/buaa-wsy-OO-2333/p/10744181.html
今日推荐