(1)从多线程的协同和步控制方面,分析总结自己三次作业来设计 策略及其变化。
多线程电梯:
由于是第一次接触多线程,我在还没有理解概念的情况下贸然上手,导致线程同步非常混乱。现在再来分析,发现思路其实还算清晰。InputHandler与调度器之间是生产者-消费者关系,中间应当有个线程安全类requestTray。调度器和各个电梯的存储队列间也是生产者-消费者关系。
IFTTT:
本次作业我认为我在多线程控制方面比电梯好很多,没有出现线程方面原因造成的bug。重要原因在于本次作业的多线程协同其实只出现在了文件操作方面,说白了是建立snapshot与测试线程修改文件之间的冲突。那么只需要在建立snapshot时上锁,同时将测试线程的所有方法上锁即可。
出租车:
我认为我这次的线程安全反而搞复杂了。InputHandler要读取电梯的状态,电梯自身要读取并修改自身的状态,请求监控器也要不断读取电梯状态。这样锁的切换之间造成的消耗很高,也容易出现bug。
(2) 基于度量来分析自己的程序结构
多线程电梯
序列图:
可以看到,本次作业的一些主要方法,比如主函数的run,电梯的update,判断同质请求的函数、进行捎带分配的函数,这些功能非常重要的函数的圈复杂度依然很高,显得很臃肿。一部分原因是因为这是电梯系列作业的第三次作业,所以自己一直在不断地在原用功能上加东西,而此时还并没有特别能灵活的利用继承和多态,高内聚低耦合的思想也没有很好的贯彻。
IFTTT
序列图:
可见这次作业的各个复杂度均比上次作业好了很多,也分散了很多。原因在于这次作业整体的设计比较明确,每个触发器有针对的方法来进行判断。但是缺点在于我把所有的判断触发器条件的逻辑都放在了SafeFile类里,导致该类复杂度非常非常高。对于这点我也没有想到太好的解决方法。
从类图也可以看出我这次的设计思路比较清晰,不像电梯那样不断往上加东西导致很杂乱无章。在主函数Run中实例化各个触发器的线程,各个触发器通过trigger函数输出信息。SafeFile里则封装了相当多的文件检测方法。
第一次出租车
序列图:
这次作业由于加上了GUI所以类图显得很乱。除去GUI的方法外,复杂度高的方法还是集中在了主要线程的run方法中,比如Taxi和Scheduler。令我惊讶的是InputHandler的类复杂度居然如此的高,查阅代码后发现是里面一个checkStatus函数用了连续的if-else和循环结构来检查100辆出租车的状态,以此作为测试接口。这也说明了在以后的设计中应当尽量减少多重if-else的逻辑结构以及switch-case结构来降低复杂度。
(3)分析自己程序的bug
第五次作业:
这次作业是第一次接触多线程,我在没有完全理解多线程机制的时候就贸然写完了程序,最后发现会出现线程阻塞,死锁以及很多无法解释的线程冲突现象,导致绝大部分有效点都没过去,不过还是遇到了好心人看出我是线程安全出了问题。。给过了几个点。。
第六次作业:
由于未被测试,因此不知道有没有什么bug
第七次作业:
这次作业最大的问题出在了同步时间上。因为我程序运行消耗时间过慢,虽然我采用了加时间来进行输出,但是在运行过程中还是会出现一些bug,而且这些bug还是随机复现的。总共被找出来两个,一个是接单的时候信用不是最高的车,一个是输出时间有误。
(4)分析自己发现别人程序bug所采用的策略
第五次作业未找到bug。第六次作业找到一个文件安全的bug,第七次作业找到两个出租车时间未同步造成的bug。
使用策略通常取决于被测者的代码可读性。。如果命名实在难以理解,我通常就采用按分类树的黑盒测试以及暴力测试。如果命名较好,我会根据程序进行分析。比如多线程电梯的运动量+捎带等边界点,出租车上下车停止时的边界点等等
(5)心得体会
多线程电梯:
首先,可能是因为第三次作业我的程序没有bug,导致我误以为自己能力还不错,结果就是多线程电梯等到周日才拿出指导书开始读。对于多线程,我也小看了他的威力,以为其只是类似于正则表达式这样的工具,从而在多线程方面我在没有彻底搞懂其原理的情况下就贸然上手编程,也没有做好完整的设计。最终的结果就是我熬夜写出了代码,但是bug却一塌糊涂,也不知道多线程的交互是哪里出了问题,debug任务艰巨,最终没能很好的实现电梯。
经验教训:搞懂多线程原理再上手写代码,可以自己先写一些小规模的程序来验证自己的猜想,否则电梯这样巨大的代码量 debug难以驾驭;设计必须先于实现,最好是在稿纸上写出逻辑的伪代码,画出类之间交互的关系图;最后,不要拖延,早点开始写,留出足够的时间。
IFTTT:
我认为本次作业和核心在于“snapshot”的建立。本次作业触发器的本质是对比两次监测下文件信息的不同,那么只需要存储文件信息的"snapshot"即可。而线程安全问题(访问冲突)也就在snapshot读取和测试线程修改之间。只要分析清楚了这个关系,线程安全方面的建立就非常容易。这次我初步体会到了设计的重要性。
第一次出租车:
这次我深深感受到了数据结构和算法底子薄弱的劣势。。人家写的bfs瞬间跑完了。。我写出来的bfs就严重影响程序运行,甚至带来不可避免的bug。下次作业我务必优化算法,减少相关bug。