抢人就完事了——OO第二单元总结

总结性博客作业

(1)从多线程的协同和同步控制方面,分析和总结自己三次作业的设计策略。

(2)基于度量来分析自己的程序结构度量类的属性个数、方法个数、每个方法规模、每个方法的控制分支数目、类总代码规模计算经典的OO度量画出自己作业的类图,并自我点评优点和缺点,要结合类图做分析通过UML的协作图(sequence diagram)来展示线程之间的协作关系(别忘记主线程)从设计原则检查角度,检查自己的设计,并按照SOLID列出所存在的问题

(3)分析自己程序的bug分析未通过的公测用例和被互测发现的bug:特征、问题所在的类和方法特别注意分析哪些问题与线程安全相关关联分析bug位置与设计结构之间的相关性

(4)分析自己发现别人程序bug所采用的策略列出自己所采取的测试策略及有效性,并特别指出是否结合被测程序的代码设计结构来设计测试用例分析自己采用了什么策略来发现线程安全相关的问题分析本单元的测试策略与第一单元测试策略的差异之处

(5) 心得体会从线程安全和设计原则两个方面来梳理自己在本单元三次作业中获得的心得体会

第一次电梯

(1)从多线程的协同和同步控制方面,分析和总结自己三次作业的设计策略。

这一次,只有一台电梯。然后调度是傻瓜式的。先来先服务。并且没有性能分。

于是……就当作单线程电梯弄了咯。

MainCtrl用于不断读取请求,然后塞到请求队列里面。

ElevatorCtrl用于不断读取请求队列,读到一个人就送一个人。不考虑捎带。

读取请求和加入请求的时候都用锁

MainCtrl相当于主控,而ElevatorCtrl只负责控制自己的那一台电梯。(虽然这个作业也只有一个电梯)

电梯本身有接人,开关门等功能。

为了支持之后的请求拆分,还有捎带和批量接人。预留了Person和Group

就很简单的设计。不过为后续作业预留了挺多可扩展的层次

(2)基于度量来分析自己的程序结构度量类的属性个数、方法个数、每个方法规模、每个方法的控制分支数目、类总代码规模计算经典的OO度量画出自己作业的类图,并自我点评优点和缺点,要结合类图做分析通过UML的协作图(sequence diagram)来展示线程之间的协作关系(别忘记主线程)从设计原则检查角度,检查自己的设计,并按照SOLID列出所存在的问题

这一次的层次化设计得不错。然后一个飙红的项目都没有,开心。

并且预留了足够可扩展的方向

(3)分析自己程序的bug分析未通过的公测用例和被互测发现的bug:特征、问题所在的类和方法特别注意分析哪些问题与线程安全相关关联分析bug位置与设计结构之间的相关性

emmm,这一次作业,基本都全a的吧。没啥bug

(4)分析自己发现别人程序bug所采用的策略列出自己所采取的测试策略及有效性,并特别指出是否结合被测程序的代码设计结构来设计测试用例分析自己采用了什么策略来发现线程安全相关的问题分析本单元的测试策略与第一单元测试策略的差异之处

这一次作业没bug

第二次电梯

(1)从多线程的协同和同步控制方面,分析和总结自己三次作业的设计策略。

就基本和上一次电梯一毛一样。只不过每到一层,就看一眼能不能带人。

原本设计的是,主控、电梯控制、电梯这三个各占用一个线程。

结果发现电梯控制去控制电梯的时候,如果两个处在不同的线程中,比较难以控制。得需要一套比较稳定的信息传送机制。并且其实要控制的节点就只有几个节点。于是直接电梯内置了电梯控制器

电梯调度逻辑:

  • 如果电梯是的,试图读取最近的请求所在楼层,如果当前没有请求,则阻塞。
  • 每一层,只接与当前运行方向相同的请求
  • 关门前的瞬间检查是否还能上人,以防止在开关门的过程中突然来了新的请求
  • 每次下人的时候,同时试图上人

主控:

  • 如果读到了新的请求,则通知电梯去取
  • 请求是分楼层去存储的,采用了hashmap,每个键值对应一个PeoPack

(2)基于度量来分析自己的程序结构度量类的属性个数、方法个数、每个方法规模、每个方法的控制分支数目、类总代码规模计算经典的OO度量画出自己作业的类图,并自我点评优点和缺点,要结合类图做分析通过UML的协作图(sequence diagram)来展示线程之间的协作关系(别忘记主线程)从设计原则检查角度,检查自己的设计,并按照SOLID列出所存在的问题

只有个别几个函数飙红。并且有几个函数是根本没用上的。整体来说,程序还是设计得不错的。就是函数多了点

(3)分析自己程序的bug分析未通过的公测用例和被互测发现的bug:特征、问题所在的类和方法特别注意分析哪些问题与线程安全相关关联分析bug位置与设计结构之间的相关性

这一次没有bug,但是……有一个函数忘记写了,造成性能极度下降。

原本有一个函数是获取电梯最近的请求的,结果忘记写了,预留的函数是返回从最底层开始找到的第一个请求,于是电梯每次都跑去最底层,gg

(4)分析自己发现别人程序bug所采用的策略列出自己所采取的测试策略及有效性,并特别指出是否结合被测程序的代码设计结构来设计测试用例分析自己采用了什么策略来发现线程安全相关的问题分析本单元的测试策略与第一单元测试策略的差异之处

这一周,又是和平的一周。没找到bug。

第三次电梯

(1)从多线程的协同和同步控制方面,分析和总结自己三次作业的设计策略。

这一次,有三部电梯。我的设计思路是这样的:

  • 每部电梯有一个函数,计算自己能把乘客带去的最优位置
  • 如果这个乘客的最优位置不是当前位置,则接客
  • 每到一层楼层,查看是否可以捎带
  • 如果没有请求,则休眠,直到被唤醒。然后去抢乘客
  • 在关门前的一刹那,试图上人,以实现最后一刻来人的时候仍能挤上电梯的功能
  • 三部电梯均空,主控中没有请求,主控已经读取到了NULL,也就是输出截止,则退出。
  • 电梯访问请求,主控添加请求,均互斥

其实最大的难点是设计“最优位置”函数

只要解决了这个函数,剩下的事情就交给三个电梯去抢人就好了。

值得一提的是,当电梯停止运行,会唤醒别的电梯,这样解决了下人的时候新增新请求以及该退出程序的时候电梯仍在休眠的问题

(2)基于度量来分析自己的程序结构度量类的属性个数、方法个数、每个方法规模、每个方法的控制分支数目、类总代码规模计算经典的OO度量画出自己作业的类图,并自我点评优点和缺点,要结合类图做分析通过UML的协作图(sequence diagram)来展示线程之间的协作关系(别忘记主线程)从设计原则检查角度,检查自己的设计,并按照SOLID列出所存在的问题

采用三电梯互抢策略的一个好处就是,可以大大减少模块的数量。只需要保证他们抢的逻辑正确就行了。

但是最优到达函数比较复杂。同时为了解决线程安全问题,以及实现尽可能多的捎带move()设计得比较复杂。

reachable函数我为了避免出错,是手动把三台电梯的可达楼层输入进去了。所以也比较复杂。

(3)分析自己程序的bug分析未通过的公测用例和被互测发现的bug:特征、问题所在的类和方法特别注意分析哪些问题与线程安全相关关联分析bug位置与设计结构之间的相关性

最优目标楼层函数写错了,造成从3楼无法到达4楼或者2楼,因为函数认为3楼已经是最优楼层……

改了这个函数之后,就ac了

(4)分析自己发现别人程序bug所采用的策略列出自己所采取的测试策略及有效性,并特别指出是否结合被测程序的代码设计结构来设计测试用例分析自己采用了什么策略来发现线程安全相关的问题分析本单元的测试策略与第一单元测试策略的差异之处

我们组的人都好坚挺。就只有我和另外一个人被发现了bug……所以我并没有找到bug

(5) 心得体会从线程安全和设计原则两个方面来梳理自己在本单元三次作业中获得的心得体会

线程安全的角度:

其实在前两次作业的时候,线程安全基本上不怎么需要考虑。毕竟一个简单的锁就行了。唯一有点难度的地方是如何安全退出。我是基于flag的判断。在进入休眠之前判断是否需要退出。

而第三次作业。我是采用了三个电梯互抢。电梯之间没有多余的沟通。所以唯二需要沟通的点就是:我在进出人我已经结束了

所谓的我要进出人,其实也就是保证请求队列的互斥。在这个地方,我因为在某些不该加锁的地方额外加了个锁,造成了死锁。后来分析这个锁其实是没必要的。于是删了之后恢复正常。

第二个是我已经结束了。在一个电梯运行完之后,如果其他两个电梯还在休眠,那么有两种情况需要唤醒其他的电梯。第一个是我下了一个人,但这个人没到目的地,第二个是我已经结束运行了,然后输出也停止,此时应该全部电梯退出线程

于是在这两种情况下,我会选择唤醒其他电梯。

关于设计原则。

为了遵循高内聚,低耦合的设计原则。我是放弃了“上帝调度器”这种设定。而选择让电梯自由竞争。

主控所做的事情,就是保证正确地存储请求,同时在请求到来的时候,通知所有的电梯。顺便提供一个锁,使得所有的电梯在访问请求集合的时候都是互斥的。

每一个电梯所做的事情是,关心自己如何更好地运送乘客。发现有乘客的时候即去抢夺资源。虽然没有全局调度这么高效。但是能保证正确性。并且性能也不会太差。

这样一来,设计的过程中,只需要关心主控和电梯这两个类内在的行为。他们如何交互的内容,只占了极小的一个部分。

猜你喜欢

转载自www.cnblogs.com/Ausar/p/10754072.html