热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

OO第二次课程总结分析

前几次的作业都是单线程的,总体来说和以前的思维模式和调试等存在着一定的挂钩,在设计上整体难度还不算太大,这次开始了多线程编程,难度可以说是质的飞跃,构思上所考虑的不止一点两点,在整体的基础上还要考

  前几次的作业都是单线程的,总体来说和以前的思维模式和调试等存在着一定的挂钩,在设计上整体难度还不算太大,这次开始了多线程编程,难度可以说是质的飞跃,构思上所考虑的不止一点两点,在整体的基础上还要考虑线程的同步安全等问题,下面针对三次作业的分析来谈谈在多线程编程上所犯的错误和得到的收获


 

一、多线程电梯

1.设计策略

       作为多线程的第一次作业,又恰逢清明假期,可以有相对充足的时间来学习多线程的相关知识和进行构思(可以说这个清明假期过得非常揪心了),因为有了前面两次电梯的积累,这次关于同质和捎带的问题并未花太多时间(但是考虑前面的代码可塑性太差,这次就进行了重构,但核心思想没变),大部分时间用在了构思三部电梯的调度和安全问题上。多线程的设计与单线程不同,在构思实现逻辑的同时还要决定开多少个线程,每个线程之间的交互影响、线程安全问题等,复杂程度大大提升。在经历了多天的思考之后,我共设计6个线程(分别为主线程(Main)、输入线程(Inputhandler)、调度器线程(Scheduler)及三个电梯线程(Elevator))。共有4个请求队列(一个总的,3个各自电梯的)。

各个线程的工作如下:

  • 主线程(1):其他线程的实例和启动
  • 输入线程(1):在收到输入结束符之前持续接受控制台输入,将有效请求(其中无效和同质都不算有效)放入请求队列
  • 调度器线程(1):当总的请求队列不为空或输入线程未结束时,不断扫描总的请求队列,根据三部电梯状态和分配原则来将请求分配给合适的电梯
  • 电梯线程(3):当自己的请求队列不为空或调度器线程未结束时,不断扫描自己的请求队列,根据电梯状态和请求来执行相应的动作

  关于线程同步控制的考虑,因为请求队列会涉及到加入请求、删除请求、从队列中取出请求及获取队列大小等操作,这都是线程不安全的,因此在对队列的操作上我都上了锁,同样,电梯状态会有改变和获取的操作,同样都加了锁。

2.程序结构分析

度量分析

类图

 

 

sequence diagram

 

  个人觉得整体架构还算满意,各个线程分工较明确,只是在具体实现时有部分代码显得臃肿,还未能做到方法功能单一,部分方法用了太多的条件分支,在代码重用性方面有些欠缺,代码的可塑性不强。

3.bug分析

  公测有四个样例没过,主要还是栽在了调度线程的问题上,分配请求的方法发生了错误,在判断电梯运动量上未做到安全,考虑不够周全,导致多个点爆了,另外时间永远是一个头疼的问题,公测终究还是被报了时间的错误。互测被找了一个格式错误,对格式边界的把握还是不够。

   测他人时还是先从格式下手,再测一些基本功能的实现(先观察代码看必要的地方有无加锁,再针对性测试),然后从边界情况来找到是否符合预期,最后就是用大一点的数据去测。

 


 

二、IFTTT

1.设计策略

  老实说,这次作业的难度比上次的要大,毕竟上次的作业有之前的作业的积累,并且给的时间相对较长,但这次作业不仅时间相对少,还涉及到文件系统,光是理解作业需求就花了挺长时间,导致最后作业完成的很糟糕。这次的构思基本就是针对一个作业开一个线程,每个线程监控每份作业相应的某个触发器和某个task,并且在创建线程的开始就为每个作业建一个状态快照,线程实时扫描文件,并实时生成更新快照,比较前后快照的不同看是否触发了相应的触发器,根据相应的触发器而做出相应的动作。各个线程如下:

  • 主线程:处理输入,如队列,线程实例和启动
  • Detail线程:处理detail这个任务
  • Recover线程:处理recover这个任务
  • Summary线程:处理summary这个任务
  • TestThread线程:提供测试接口
  • Watch(监控)线程:根据触发器不同让哪个任务执行

  关于线程安全的考虑,对文件的操作会导致线程不安全,因此这块利用锁来实现同步,保证同一时刻只能有一个线程在对文件操作,避免应线程不安全而导致难以预料的错误。

2.程序结构分析

度量分析

类图

sequence diagram

  这次的程序可以说写得很糟糕,由于时间的不足,没有考虑监控目录的情况,并且程序的主线程写了太多,显得很臃肿,应该将输入处理等移出,主线程只负责启动其他线程方为上策。同时,Safefile类忘记提供获取最后一次修改时间等方法。总之,这次的构思有些问题,程序结构设计的不是很合理。

3.bug分析

  这次互测被找的bug是最多的一次,因为没有实现目录的监控,这部分被找了bug,同时,recover也未能实现,导致被测了许多bug,也是对自己的反思吧,毕竟自己没有实现那部分的功能。

       这次互测就是针对几种触发器和几种任务的组合,一一进行几组测试,从而找出与预期结果相悖的点,针对找到的点,找到对应的代码,看关联的方法或其他,再针对地找其他bug。

 


 

三、出租车

1.设计策略

  因为出租车是相互独立的,互不影响,故考虑每辆出租车一个线程,每辆出租车都有各自的私有属性,都能进行抢单、运送等动作,且出租车之间没有交互,各自独立。同时因为每辆出租车要从抢单出租车中选出合适的,故每个出租车都设了一个属于自己的请求队列,调度器负责为乘客选择合适的出租车,出租车负责将乘客送往目的地。因此,程序的线程如下:

  • 主线程:读入地图信息、声明静态常量、线程实例及启动
  • 输入线程:输入请求并将有效请求(无效、同质均不算)加入队列
  • 出租车线程(100):出租车的各种运行(随机跑或按最短路径跑)
  • 调度器线程:选出抢单出租车并进行派单

  关于线程安全的考虑,本次总的请求队列是一个共享资源,故是非线程安全的,在对队列的操作中都加了锁,由因为调度时要获得出租车的状态、信用度即位置等,所以在出租车的状态、信用度及位置等的set,get方法上均加了锁。

2.程序结构分析

度量分析

类图

sequence diagram

  这次程序的方法我尽量地去写得很短,只实现某一个功能,其他部分各人认为写得算是比较简洁,但调度器的run方法还是用了太多的循环和条件判断,导致度量变红,这一块应该改进,抢单可以另外用一个方法实现,而不用写在run里还有Taxi的判断走哪条路的方法复用性不够强,代码的相同地方过多,可以通过传目的地参数的方法进行此部分代码的复用。

3.bug分析

  这次交得急,没有写测试接口,被报了一个设计缺陷,同时因为gui中算最短路径的方法耗时太长,在输出时我用的是假时间,但gui上跑得较慢,因为这个原因,接单和服务状态下车要比等待时跑的慢,被测试者找了bug,还有因为在遍历数组时条件判断不够充足,导致程序在一定间隔内输入的多条请求引发NULLpoint的crash。

  这次找bug为了能保证出租车一定能接到单,我找的时候让出租车初始位置从某个点出发,便于进行测试。

 


 

最后的心得体会

  经历过这最痛苦的三周,对多线程编程也有了自己的体会。在多线程电梯刚开始使用锁时,傻傻地锁住了sleep,导致线程之间不能并行,这个让我困惑了许久,后来逐渐缩小锁的方法的范围才解决。多线程的运行机制比单线程复杂得多,在动手之前要足够了解这种机制,不然真的发生了预料之外的后果你也会手足无措,所以事先设计构思、想好哪些资源需要共享,哪些需要同步,哪些线程是独立的,哪些是交互的,我认为这种考虑在多线程编程中是非常有必要的。


推荐阅读
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • 第四章高阶函数(参数传递、高阶函数、lambda表达式)(python进阶)的讲解和应用
    本文主要讲解了第四章高阶函数(参数传递、高阶函数、lambda表达式)的相关知识,包括函数参数传递机制和赋值机制、引用传递的概念和应用、默认参数的定义和使用等内容。同时介绍了高阶函数和lambda表达式的概念,并给出了一些实例代码进行演示。对于想要进一步提升python编程能力的读者来说,本文将是一个不错的学习资料。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • STL迭代器的种类及其功能介绍
    本文介绍了标准模板库(STL)定义的五种迭代器的种类和功能。通过图表展示了这几种迭代器之间的关系,并详细描述了各个迭代器的功能和使用方法。其中,输入迭代器用于从容器中读取元素,输出迭代器用于向容器中写入元素,正向迭代器是输入迭代器和输出迭代器的组合。本文的目的是帮助读者更好地理解STL迭代器的使用方法和特点。 ... [详细]
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
author-avatar
等着日落看日出222
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有