OO电梯作业总结

这三周的作业和课堂内容以及OS的课上内容都相同,都是关于多线程方面的知识。在这次作业中由浅入深布置了三项多线程电梯方面的作业,让我们在实践中感受了多线程的工作原理以及各项需要注意的要素。

一、第一次作业

第一次作业是典型的生产者消费者问题,只不过生产者不必考虑容器装满的特殊情况。在这次电梯作业中电梯只需要将乘客送往目标楼层,不需要解决沿路搭顺风车等其他需要解决的特殊情况。当负责输入的生产者停止时,设置一个共享的结束变量结束整个电梯的运行,整个电梯的运行结构如下图所示:

如图所示,整个电梯总共包含2个线程,即电梯线程和输入线程,两者通过结束信号进行通信。同时两者共享一个共享变量:等待队列。在多线程环境下势必会出现两者共同访问导致数据冒险的情况。我采取的解决方法是将等待队列类中的每个函数设定为静态函数,并加上synchronized修饰。通过百度和自身的实践,这样操作的实际效果是对类本身进行加锁,即当一个静态函数被调用时禁止其他静态函数被调用。这样操作的确可行,但是由于是在函数上加锁,性能方面不如对特定变量,但好处是能够有效地确保正确性。

本次作业的类图如下所示:

代码分析如下:

可以看见在电梯类中我的写法没有做到完全对任务进行细分,而是一个run方法走到底,因此代码的复杂性较高。在接下来的任务中我注意到了自己的问题,对任务进行更细的划分。

BUG分析

这一次作业由于比较简单,在互测以及强测中都没有发现任何BUG。

第一次电梯作业总结

第一次作业是对多线程的试水,在其中我初步感受到了多线程的设计风格,同时大致确立了电梯问题的整个架构。在接下来的作业中都是沿用输入队列,等待队列以及电梯3类的架构进行设计。

二、第二次作业

这一次的电梯作业相比上一次的电梯作业增加了2个难点。第一,这一次的电梯是ALS电梯,需要额外考虑2个环节。首先电梯在上升时需要考虑对同方向乘客的捎带,同时由于电梯内部可能有多于一个乘客的情况,因此需要额外增加一个队列记录电梯内部的人员请求。第二,这一次作业增加了对于CPU运行情况的检查,因此无法在这一次作业中使用轮询算法,必须运用锁控制查询,降低CPU使用率。

受到OS课程的影响,相比较synchronized,notify(),我偏向更加简单直接的Semaphore,因此在这次作业中我主要使用Semaphore实现进程同步和互斥。

首先列出这次作业的主要流程架构:

捎带的解决方法如图中所示。首先创造运行队列,将电梯中的所有人的请求加入运行队列。其次在每一层都检查等待队列中是否有满足捎带条件,如果有则加入运行队列中。最后再谈谈我是怎么解决轮询问题的,我所采用的方法是最简单的方法,即在每次搜索结束之后进行sleep操作,减少CPU使用。当然合理利用信号量肯定是最高效的解决方案,因此在第三次作业中我采取了另一种方案。

以下是本次作业的类图以及代码分析:

由于这次电梯作业中啊需要使用到大量的if判断,包括电梯的运行方向,查找操作以及判断当前层数是否为0等,因此这次的代码复杂度普遍较高。可以改进的做法是对函数功能进行进一步的细分。在这一次作业中为了更高的准确性和代码的直观性,我没有进一步细分,导致代码复杂度较高。

BUG分析

在中测中主要出现了一个BUG,就是CPU超时,通过sleep()便可顺利解决。然而强测只得了26分,原因特别简单,也特别愚蠢。在电梯向下运行进行顺带判断时,不慎将>写成了<,直接导致测试点全挂。也算是一个教训。代码上任何一点微小的错误将导致整个崩盘,因此必须在每次中测时做好课下测试,写自己的评测机,最大限度地杜绝这种情况再次出现。

三、第三次作业

第三次作业本质上相较于第二次作业增加了2个方面。第一是电梯变多了,因此需要创造更多的运行队列,同时对等待队列需要进行访问加锁控制。第二点也是这次作业的难点,由于部分请求无法由一个电梯完成,因此需要采取合理可行的措施实现多电梯协作。对于该问题的解决我通过改写PersonRequest类实现,在其中添加了label,realend,available三个变量进行实现,对这种特殊情况的处理在等待队列中实现,具体方法如下图所示:

对于我的处理架构,在这次作业其实还有一个隐藏的难点,那就是一台电梯关闭时机的判断。当输入线程关闭时且等待队列为空时不能够关闭电梯,因为label=1的运行队列中的请求会重新加入等待队列。解决方法有2个,第一是让每个电梯线程能够访问其他电梯的运行队列,当输入线程关闭,所有的运行队列都为空并且等待队列为空时,同时结束所有电梯线程。我认为电梯运行队列应该由本电梯完全掌握,因此采取第二种做法,在输入线程结束并且等待队列为空的情况下,当等待每部电梯都处于查询等待队列状态并且第一次查询未找到时,将每部电梯的一个特征变量设置为1,当所有特征变量设置为1时,同时关闭所有电梯。

总体上这一次作业的队列类以及电梯很好地复用了上一次的作业,对电梯的修改是增加了对label=1任务的特殊处理,对满员情况的判断以及在线程结束时的特殊处理。对队列的修改包括增加了2个运行队列,以及在将输入线程的请求读入等待队列时判断可执行的电梯,写入available,同时对不可执行的电梯作label=1的特殊处理,第三次作业的类图以及代码分析如下图所示:

这一次的代码风格明显有很大的不足之处,原因之一是这一次的作业大幅度复用了上一次作业的样板,因此在电梯类中代码的复杂度较高。第二个不足之处是没有在电梯类中实现继承或者创建一个泛化的电梯类。这次作业中三个电梯明显有很大的相同点,只是在个别属性上不同。将代码进一步细化并且熟练实现以及掌握继承是需要在接下来的学习中注意的地方。

BUG分析

这一次的作业比上一次更加悲剧,中测未能通过。最终发现原因也特别简单,在电梯顺带时完全沿用了上一次的模板,忘记进行修改,导致电梯在等待队列提取请求时根本就没有判断当前楼层是否能停靠,直接导致整个测试崩盘。这也给我带来了第二个教训,那就是不能太急着写代码,而是应该先详尽地对整个任务进行细节分析,列出所有需要扩展的地方再进行修改,否则就会像这样在细节处崩盘。

四、互测BUG分析策略

首先这一次的电梯作业测试难度明显上升,无法运用简单的控制台输入输出得到正确结果,因此在正式进行测试之前我通过讨论区的指示自己写了一个评测机,在另一个文件中间段输出自己设定的指令,同时替换输入线程的方法,通过process类读取文件中的指令实现按照特定时间输入的效果。

第一次作业互测:这一次作业的互测其实并没有太多BUG可以发现。我注重两方面的BUG,一是对电梯关闭时机的测试,第二则是电梯是否能够正确运行。结果并没有在互测中发现BUG。

第二次作业互测:这一次作业我受到了多次攻击,主要来自于强测的错误,将>误写成<.这一次的强测我注重两个方面的测试,首先是在边缘时间投放测试点,即电梯关门的瞬间投放请求,如果在开门时搜索等待队列则会错过该请求。第二是对电梯运行通过0层的测试,在互测中共DE出2个BUG。

第三次作业互测:由于没有通过中测,因此很不幸没有进入第三次互测。

五、心得与体会

多线程处理无疑是每个程序猿的基础技能,这次的作业只是为我们开了一个非常初步的头,接下来还有无穷无尽的知识点需要我们自己去探索。在这次作业中虽然成绩不够理想,但是静下心来还是获得了不少的经验和教训,包括对编程方法的反思,对细节的把握,以及代码风格架构的进一步优化,这都是我需要在接下来的作业中不断改进的地方。在接下来我需要更进一步,积极了解阅读关于JAVA方面的常识和知识,使得自己具有更加强大的专业技能,同时让自己不至于在细节处再次翻车。

oo第二次总结作业的更多相关文章

  1. OO第二单元——电梯作业总结

    前言 本单元作业主要以设计电梯来实现多线程编程.本章主要学习了如何使用多线程以及如何确保多线程安全,从电梯的调度策略中学会了如何简单地使用synchronized锁来控制线程安全. 首先,明确锁的两个 ...

  2. OO第二单元电梯作业总结

    目录 目录一.第一次作业分析设计策略基于度量分析程序结构二.第二次作业分析设计策略基于度量分析程序结构三.第三次作业分析设计策略基于度量分析程序结构四.分析自己程序的bug五.发现别人程序bug所采用 ...

  3. OO第二次博客作业——电梯调度

    OO第二次博客作业——电梯调度 前言 最近三周,OO课程进入多线程学习阶段,主要通过三次电梯调度作业来学习.从单部电梯的傻瓜式调度到有性能要求的调度到多部电梯的调度,难度逐渐提升,对同学们的要求逐渐变 ...

  4. oo第二单元作业总结

    oo第二单元博客总结 在第一单元求导结束后,迎来了第二单元的多线程电梯的问题,在本单元前两次作业中个人主要应用两个线程,采用“生产者-消费者”模式和共享数据变量的方式解决问题.在第三次作业中加入多个电 ...

  5. OO第二次博客作业—17373247

    OO第二次博客作业 零.写在前面 OO第二单元宣告结束,在这个单元里自己算是真正对面向对象编程产生了比较深刻的理解,也认识到了一个合理的架构为编程带来的极大的便利. (挂三次评测分数 看出得分接近等差 ...

  6. 【OO学习】OO第二单元作业总结

    OO第二单元作业总结 在第二单元作业中,我们通过多线程的手段实现了电梯调度,前两次作业是单电梯调度,第三次作业是多电梯调度.这个单元中的性能分要求是完成所有请求的时间最短,因此在简单实现电梯调度的基础 ...

  7. OO第二次作业总结

    OO~第二次作业总结 连续三周的电梯作业结束了,总的来说这三次作业做的还算平稳,既没有被刀,也没有刀中别人.那么接下来开始谈谈我对这三次作业的认识. 一.设计策略 我三次作业的设计思路基本上是相同的, ...

  8. 电梯也能无为而治——oo第二单元作业总结

    oo第二单元作业总结 一.设计策略与质量分析 第一次作业 设计策略 在第一次作业之前,我首先确定了生产者--消费者模式的大体架构,即由输入线程(可与主线程合并)充当生产者,电梯线程充当消费者,二者不直 ...

  9. OO第二单元作业小结

    前言 转眼已是第九周,第二单元的电梯系列作业已经结束,终于体验了一番多线程电梯之旅. 第一次作业是单电梯的傻瓜调度,虽然是第一次写多线程,但在课程PPT的指引下,写起来还是非常容易:第二次作业是单电梯 ...

随机推荐

  1. 转:Redis和Memcache的区别分析

    Redis和Memcache的区别分析  原文链接:http://blog.csdn.net/u013474436/article/details/48632665 简单区别: 1. Redis中,并 ...

  2. Laravel基本使用

    laravel一.简介二.运行环境要求 1.php 版本>=5.5.9 2.Mcrypt PHP扩展 php的加密扩展,提供多种加密算法 3.openssl扩展 对传输的数据进行加密 4.mbs ...

  3. Android深入四大组件(四)Android8.0 根Activity启动过程(前篇)

    前言 在几个月前我写了Android深入四大组件(一)应用程序启动过程(前篇)和Android深入四大组件(一)应用程序启动过程(后篇)这两篇文章,它们都是基于Android 7.0,当我开始阅读An ...

  4. django源码研究

    研究django源码一年,从启动django开始

  5. java indexOf 和 split的用法

    1.java 的 indexOf 方法 ,如果存在 则 指定的字符串的开始位置,如果不存在 则返回-1: 2.java 的 split的方法:将一个字符串分割为子字符串,然后将结果作为字符串数组返回. ...

  6. c# 调用 c dll 例子

    // case 1 传递 int* ///////////////////////////////////////////// extern “C” __declspec(dllexport) int ...

  7. 在 O(1) 时间删除链表结点(C 和 Python 实现)

    (说明:本博客中的题目.题目详细说明及参考代码均摘自 “何海涛<剑指Offer:名企面试官精讲典型编程题>2012年”) 题目 给定单向链表的头指针和一个结点指针,定义一个函数在 O(1) ...

  8. sequelize 学习之路

    如果你觉得Sequelize的文档有点多.杂,不方便看,可以看看这篇. 在使用NodeJS来关系型操作数据库时,为了方便,通常都会选择一个合适的ORM(Object Relationship Mode ...

  9. python笔记8-多线程threading之封装式

    执行函数 1.先写一个执行函数,用来实现做某件事情,不同的人吃火锅用一个参数people代替. # coding=utf-8 import threading import time def chiH ...

  10. INSERT CLAUSE

    a.single table insert INSERT INTO jobs(job_id,job_title,min_salary,Max_Salary) VALUES('IT_PM','PROJE ...