• OO第二次博客作业


    又完成了三次OO作业,这三次有关多线程的作业对我来说可谓是很大(保护头发)的挑战。

    一、从多线程的协同和同步控制方面,分析和总结自己三次作业来的设计策略及变化

      第五次作业是设计⼀套由 3 部电梯组成的多电梯调度系统,通过采⽤线程机制,在第三次作业所实现程序的基础上完成新的调度系统程序。第三次作业是调度器持续监控电梯的运动状态变化,从而扫描队列找到相应的请求进行捎带调度。而第五次是采用多线程设计,可以有两种设计思路,一种是调度器拥有对所有电梯线程对象的引用,把电梯线程当成一般对象进行访问,另一种是设置一个status board,电梯线程把自己的状态发布到board,调度器从中读取电梯状态。中心调度器关注请求到电梯的分配(强调运动量或负载均衡);电梯调度器关注捎带处理。

       第六次作业是实现一个监控程序,针对给定监控范围内的监控对象,以扫描方式探查监控对象相关属性的变化,从而触发规定的处理动作。我的思路是每一个输入所要求的监控由一个tigger线程来监控,tigger线程通过主动扫描或检查外部世界,建立快照snapshot(多叉树)并实时更新快照,查看检测对象是否发生renamed,modified, path-changed, size-changed四种变化来设置信号量,一旦summary,detail或recover的信号量被改变就触发控制线程,执行相应动作将信息独立输出到指定文件。在这个过程中要特别注意到实践线程的主从协同模式,采用主动模式的线程需要与外部环境对象进行交互,采用被动模式的线程需要按照一定协议与主动模式线程交互。在完成了线程设计、线程同步设计之后,锁的选择也是关键问题。所有共享对象都应设计为线程安全的类。

      第七次作业是模拟出租车的乘客呼叫与应答系统。我的思路是调度器类从用户请求队列中不断取出到时间的请求,将其放入合适的出租车,出租车线程会根据输入的请求自动运行,而输入线程在另一边可以将输入的请求放入该请求队列,实现了测试的需求。由于出租车的位置、服务/行驶状态、信用在不断发生变化及抢单窗口具有时效性,这里我仍旧采用了快照的方法实现对出租车的监控。这次作业仍需注意实践线程安全设计,同时也要注意类的均衡性等。

    二、基于度量来分析自己的程序结构

    1.第五次作业

      由于一开始对多线程的不太理解以及电梯分配问题、捎带问题等,第五次作业完成的非常仓促,捎带功能并没有实现,问题很大,就不仔细分析程序结构了,对于这次作业我打算之后的空闲时间继续研究一下,这里就不多说了。

    2.第六次作业

     

      我的思路是每一个输入所要求的监控由一个tigger线程来监控,tigger线程通过主动扫描或检查外部世界,建立快照snapshot(多叉树)并实时更新快照,查看检测对象是否发生renamed,modified, path-changed, size-changed四种变化来设置信号量,一旦summary,detail或recover的信号量被改变就触发控制线程,执行相应动作将信息独立输出到指定文件。

      在这次代码作业中,我也体现出了较多的问题。其一是未对触发器和处理任务进行适当的抽象,形成继承层次,导致出现较多的剪贴代码(进行文件的访问和处理)。其二是使用过多线程,每个监控构造一个线程。其三是我的代码类的均衡性仍然有待改进,tigger类接近上帝类。

    3.第七次作业

     

      本次作业要求设计的是一个模拟出租车与乘客交互的系统。乘客发出请求,程序能调度合适的出租车应答请求。输入输出测试要求具体见上文。

      根据实际,我们可以自然地抽象出这样几个类:Taxi,Customer,Map,分别表示出租车,乘客,地图。此外还需要一些辅助的类来调度整个系统,如请求队列类,输入类,调度器类等。

    1. 地图能处理给定的地图文件,得到地图文件的邻接表表示形式。便于后面处理最短路。大小为80x80的网格。地图为连通图,且只有相邻的两点才有可能有边相连,边为双向边。出租车、顾客分布在点上。其中出租车的起始坐标通过随机产生,其后按照一定的运行规则运动。
    2. 出租车作为一个可以run的对象,能在没有任务时根据相应规则到处游走,在有任务时及时响应并完成任务。出租车的状态转换规则指导书已经说明,此处不再赘述。
    3. 乘客可以抽象为一个请求,包含起始位置与终止位置。
    4. 请求队列负责装载用户的请求。
    5. 输入类提供将控制台输入转换为用户请求的能力,将请求加入请求队列。
    6. 调度器类负责处理请求队列中的用户请求。

      为此,程序采用SOLID原则中的单一职责原则,每个类都只管理自己的事,例如出租车只负责导航与运行,乘客只负责上车等。

      从上面的类的职能分析我们可以看到,出租车类和顾客类是我们这次工程的主要核心,而它们的桥梁则应该由一个调度器来分配执行。根据生活经验与本次指导书要求,我们可以设计出如下应答方式:乘客在发出请求的瞬间产生一个呼叫区域,这个区域持续3s,3s内任何到达该4x4区域(包括边界)的车辆都会给该乘客发请求(投简历),乘客在3s后作出决定,从简历箱中选出此刻能响应的最优出租车,然后呼叫,出租车便立即去往乘客所在地,将其接走,送到目的地后重新回到等待服务状态。

      总而言之,是调度器类从用户请求队列中不断取出到时间的请求,将其放入合适的出租车,出租车线程会根据输入的请求自动运行,而输入线程在另一边可以将输入的请求放入该请求队列,实现了测试的需求。

    三、分析自己程序的bug

    1.第五次作业

      写的就不完全,有关捎带的问题都没实现,就不分析bug了吧。

    2.第六次作业

      (1)SafeFile类中的delete方法在删除目录时程序会crach,原因是在删除目录时递归有问题。

      (2)在监测目录时,当目录深度大于等于2时,由于我的tigger在判断目录的子目录的子文件时递归写错,造成了程序检测不到目录的子目录的子文件的变化,什么都不输出。

      总结这两个错误,发现都是跟目录相关的递归出了问题,在有关递归的写法上,我得再好好学习一波。

    3.第七次作业

     (1)指导书关于出租车的规定的第七条为出租车有信用积累,初始所有车信用为 0,每参与抢单一次该出租车信用度立即加 1,每成功服务顾客一次(即把乘客从出发点成功送到目的地后)该出租车信用度立即加 3。

      在一次测试中对于第一条指令有 12 46 21 37 四辆车参与抢单(这里的输出显示四辆车的信用度为0,这里就应该不对了,因为输出的状态应该是窗口结束后的参与抢单的出租车的状态)。对于第二条指令,发现21号出租车再次参与抢单,但是后面输出的信用度却是0,不是2,也不是1(如果是1则可认为是输出的是抢单时的状态),因此这里应该是错了。同时通过对于代码的查看也印证了这一错误。

      这个错误产生的原因是我没有好好阅读指导书,以为抢单成功信用才加一,感觉自己十分愚蠢。

      总结后两次作业,发现自己的bug都与线程安全问题和设计结构问题无关,都是在具体实现方法的时候出现的逻辑上的一些失误。

     

    四、分析自己发现别人程序bug所采用的策略

    1.第五次作业

      先将公测测试集测试完,然后利用错误分支树构造简单测试样例,发现自己好像拿到了一个大佬的,并没有查出错来。在大概阅读了对方的代码后,发现确实是一个大佬的代码,整个程序的写法十分接近工程,设计原则都被很好地满足,打算学习一波。

    2.第六次作业

      同样也是先将公测测试集测试完,然后利用错误分支树构造测试样例,发现我拿到的这个同学监控文件部分写的很好,但整个程序不能监控目录。

    3.第七次作业

      第七次作业的公测就是检测输入的合法性,剩下的功能性测试都得自己来,我先按照错误分支树构造了简单的测试样例进行测试,然后随意测试了多组构造数据发现都正确,最后根据他给出的类图和文档介绍阅读代码,发现完全没毛病。

      综上,作业写到这里,根据错误分支树构造样例进行测试虽然不失为一种方法,但更好的办法还是阅读对方的代码,判断有没有逻辑上架构上线程安全上的错误。

    五、心得体会

      最最重要的一点,一定要仔细阅读指导书,看清楚每一条需求,根据需求分析我们需要哪几个类,每个类的作用是什么,根据类的作用分析这个类需要哪些方法,心里大概有个谱以后程序就能完成的又快又好。多看客服群和issue也有很大的帮助。

       多学习多交流少睡觉多写代码,不然这学期还没上完oo就gg了。

  • 相关阅读:
    《信息学奥赛一本通》提高版题解索引
    QUERY [ 单调栈 ]
    [ 模拟退火 ] bzoj3860 平衡点
    [ 考试 ] 7.12
    离线和简单分治
    [ 校内OJ ] NOIP2019模拟赛(九)
    校内模拟考 (一)
    Codeforces 808E
    学习笔记—点分治
    [ 线段树+哈希 ] 反等差数列
  • 原文地址:https://www.cnblogs.com/qinfeng918/p/8974465.html
Copyright © 2020-2023  润新知