BUAA-OO-2024-第二单元总结

孙锐毅-22373500 学生 2024-04-20 14:25:39

目录

  • OO第二单元总结
  • 第一次作业
  • UML类图
  • UML协作图
  • 总设计
  • Main
  • Input
  • Schedule
  • Elevator
  • Decision
  • Request
  • Person
  • 同步块和锁
  • 调度器设计
  • Bug分析
  • 第二次作业
  • Uml类图
  • UML协作图
  • 新加入的设计
  • Reset
  • 修改的设计
  • Input
  • Schedule
  • Elevator
  • Myrequest
  • 同步块和锁
  • 调度器设计
  • 调度策略
  • Bug分析
  • 第三次作业
  • UML类图
  • UML协作图
  • 新增设计
  • SingleSchedule
  • DoubleCarElevator
  • Flag
  • DoubleCarReset
  • 更改设计
  • TotalSchedule
  • NormalElevator
  • NormalReset
  • Decision
  • 线程关系
  • 同步块和锁
  • 调度器设计
  • 调度策略
  • Bug分析
  • 总结
  • 稳定内容
  • 任务目标
  • 变化内容
  • 结束条件
  • 分配策略(调度器的变化)
  • 重置请求(电梯的变化)
  • 心得体会
  • 线程安全
  • 层次化设计
  • 碎碎念

OO第二单元总结

第一次作业

UML类图

img

UML协作图

img

总设计

7个类

Main

主要负责启动Input,Schedule,Elevator线程

Input

输入线程,读取请求输入,并将其加入到总请求队列waitrequest中

Schedule

调度器线程,从waitrequest中获取请求并分配到各个电梯中

Elevator

电梯线程,根据获得的decision执行每一步操作,完成运送乘客任务

Decision

根据电梯当前状态判断电梯下一步应该进行的操作

Request

请求类,多线程间的共享对象,其中的方法需要加上锁synchronized来保证线程安全

Person

乘客类,储存请求人员的信息

同步块和锁

在第一次作业中,我设置的线程类有Input,Schedule和Elevator三个类,这三个类的共享对象其实都是请求队列。因此,我将Request类里的方法进行了同步设置,都加上了锁来进行管理。

这样加锁之后,Input类和Schedule类对总请求队列waitrequest的管理是同步的,Schedule类和每个Elevator的局部队列也是同步的,从而保证了线程安全的问题

调度器设计

在第一次作业中,调度器发挥的作用其实并不大,因为每个乘客都指定了需要搭乘的电梯,Schedule类的作用就只用从总队列中取出乘客,再识别出其需要搭乘的电梯,最后加入到相关电梯的乘客队列中即可。

在这个过程中,Schedule线程与Input线程两者通过waitrequest总请求队列联系,Input线程充当生产者,Schedule线程充当消费者,当waitrequest队列为空时,Schedule线程等待,Input线程向waitrequest队列加入时,将Schedule线程唤醒。当Input线程结束时,会将waitrequest队列的结束标志置1,从而让Schedule线程读取到后进入结束阶段。

同时,Schedule线程与每个电梯线程通过电梯各自的request队列相联系,Schedule线程充当生产者,Elevator线程充当消费者,当request队列为空时,Elevator线程等待,Schedule线程向request队列加入时,将Elevator线程唤醒。当Schedule线程结束时,会将request队列的结束标志置1,从而让Elevator线程读取到后进入结束阶段。

Bug分析

第一次作业在最终的呈现中是没有出现Bug,但是在编写过程中,我仍遇到了一些问题。

第一个是关于多线程的理解问题,第一次遇到多线程,一开始还有些懵,但好在也是通过查找资料,学习等摸到了一些皮毛。

另外的一个是关于线程结束的问题。线程的开始十分简单,但是对线程结束,需要考虑什么时候结束,线程怎么判断应该结束的问题。第一次作业的任务中可以发现,Schedule类结束的标志是请求队列为空即可,Elevator类则是请求与电梯中的人均为空即可结束。对于线程判断结束,我是在Request类中设置了结束标志,让每个线程通过判断结束标志是否置1来帮助确定结束。

第二次作业

Uml类图

img

UML协作图

img

新加入的设计

Reset

存储Reset指令的相关信息,保障电梯Reset过程的进行

修改的设计

Input

加入对读入指令的判断,分别加入waitrequest总队列的不同类型的分队列

Schedule

加入关于Reset指令的判断与处理,将Reset之后产生的换乘请求加入回waitrequest总请求队列中

Elevator

加入关于Reset指令的判断与处理,能够改变电梯属性并完成Reset操作

Myrequest

在第一次作业的person类请求队列的基础上,加入reset类的请求队列,使得能够存储并输出reset请求

同步块和锁

在第二次作业中,我设置的线程类仍是Input,Schedule和Elevator三个类,这三个类的共享对象仍然都是请求队列。但是在第二次作业中新加入了对电梯的Reset请求,对于Reset请求的处理,除了原来的共享对象request队列外,电梯内的乘客people也需要同步控制,从而避免在Reset过程中出现乘客遗漏的情况。因此在第二次作业中在进行电梯Reset的处理时,我加上了关于电梯内部乘客people的锁,使在将电梯未处理请求与电梯内乘客的换乘请求统一加回waitrequest总请求队列的时候,不会出现同步问题,从而保证了线程安全。

调度器设计

在第二次作业中,取消了第一次作业中乘客指定电梯运送的条件,将由调度器决定将乘客请求分给某一步电梯进行运送。因此Schedule类就需要在第一次作业的基础上进行扩充,需要根据每名乘客的相关信息(如起始楼层,目标楼层),并结合当前每部电梯的情况(如当前所在楼层,运行方向,运行速度等等)进行分配请求的判断。

在这个过程中,Schedule线程与Input线程两者依旧通过waitrequest总请求队列联系,Input线程充当生产者,Schedule线程充当消费者,当waitrequest队列为空时,Schedule线程等待,Input线程向waitrequest队列加入时,将Schedule线程唤醒。当Input线程结束时,会将waitrequest队列的结束标志置1,但是Schedule类的结束在这次中不仅仅要看waitrequest队列是否为空,还需要考虑电梯Reset所可能产生的新的请求。

Schedule线程与每个电梯线程通过局部队列request联系。在第一次作业的基础上,加入了关于reset请求的处理。如果Schedule类要想Elevator类分配reset请求,则先将电梯中的reset标志位置1,再将reset请求加入电梯队列request中,让电梯执行reset操作,避免出现无法及时响应reset请求的情况。在电梯reset操作开始后,Schedule类还需要将电梯由于换乘产生的新的乘客请求加回waitrequest总请求队列。

调度策略

可能使用的调度策略有:

  1. random分配

    将乘客随机分配给各个电梯

  2. 均匀分配

    将乘客均匀分配给各个电梯(模6大法)

  3. 分配给接到乘客请求所需时间最少的电梯

    仅考虑接到乘客时间的最短“路径”方法

  4. 调参大法

    综合考虑各个因素(电梯接到乘客时间,电梯现请求数量,电梯人数,预计完成时间等等),并设置相关参数,即各个因素的权重,最后综合考虑分配。

  5. 影子电梯

    模拟电梯的运行,分配给花时间最少的电梯。即在输入线程获得一个请求时,深克隆电梯类进行模拟从而将请求分配各所花费时间最少的电梯;

在这次作业中未能实现影子电梯,没有能够体会到号称最强的调度策略。在实际体验中发现,均匀分配的总性能并不会太差,比random的性能更好。另外编写了“接待最短时间”与“调参大法”的策略代码,后来发现还并没有比均匀分配效果好多少,甚至会出现更差的情况。(也许该换回均匀分配 > _ <)

Bug分析

这次作业中出现了一个bug,是在程序输出“reset accept”和电梯输出“reset begin”之间输出的“arrive”指令数量超过了3条。导致这个Bug的原因是在程序接受到reset指令跟电梯进入reset状态之间的时间间隔太大,导致电梯在这段时间内做出了过多的移动操作。我在一开始电梯进入reset操作,是由decision判断电梯的resetrequest队列不为空就开始进行。在reset操作的一开始电梯自身将reset标志位置1,此时才算电梯进入reset状态。在接受到这个reset标志位置1后,Schedule类将不在为该电梯分配请求。因此,我将电梯进入reset状态的时间前移,在Schedule类为相关电梯分配reset请求时,就将改电梯的reset标志位置1,使电梯进入reset状态,电梯进入reset操作也变为判断reset标志位,使得电梯在收到reset请求后能够尽快进行reset操作,从而在程序输出“reset accept”和电梯输出“reset begin”之间电梯操作减少。

第三次作业

UML类图

img

UML协作图

img

新增设计

SingleSchedule

改为两层调度器模式,此为内层调度器,为所管理的电梯分配请求,完成从单轿厢到双轿厢的转换(结束单轿厢进程,开始双轿厢进程),完成双轿厢电梯的换乘

DoubleCarElevator

双轿厢电梯,与单轿厢电梯类似,改变了运行楼层,新增了换乘方法

Flag

标志类,用来管理双轿厢电梯的换乘操作

DoubleCarReset

用以存储双轿厢电梯重置请求的信息

更改设计

TotalSchedule

改为两层调度器模式,此为外层调度器,向内层调度器分配请求

NormalElevator

单轿厢电梯,即先前作业电梯

NormalReset

存储单轿厢电梯换乘请求,即先前作业请求

Decision

加入关于双轿厢电梯的运行判断

线程关系

在第三次作业中,我设置的线程类变为Input,TotalSchedule,SingleSchedule,NormalElevator,DoubleCarElevator五个类。

Input类和TotalSchedule类通过总请求队列waitrequest联系。TotalSchedule将waitrequest中的请求分配到SingleSchedule中,SingleSchedule根据当前状态(即为单轿厢电梯还是双轿厢电梯),向NormalElevator或者DoubleCarElevator分配请求。如果TotalSchedul向SingleSchedule分配的请求为双轿厢重置请求,则SingleSchedule会使NormalElevator进入结束阶段,并新开始两个DoubleCarElevator线程。

同步块和锁

这次新增的一个需要重点考虑同步问题的地方就是双轿厢电梯的换乘。因此我单独设置了Flag类,用以完成双轿厢电梯的同步控制。对换乘楼层设置occupied标志位,如果有电梯抵达换乘楼层,将标志位置1,离开换乘楼层,将标志位置0。电梯能否抵达换乘楼层要根据occupied标志位的状态来决定。FLag类中有更改occupied标志的方法,均被设置同步控制。

调度器设计

本次作业由于出现了双轿厢电梯,因此我将原先的单层调度器模式,改变为了双层调度器模式。外层调度器将请求分配给内层调度器,内层调度器再将请求分配给电梯,从而能够较好的处理双轿厢的问题。

调度策略

由于新增了双轿厢电梯,因此调度策略会发生不同的变化。当然random分配与均匀分配不会有太大改变,“接待最短时间”需要考虑是上轿厢还是下轿厢,“调参大法”需要更改参数设置。(影子电梯没有实现>_<)

Bug分析

本次作业出现了一个bug,是wait/notify问题。进过分析我发现,死锁的产生主要是发生在双轿厢电梯的换乘过程中。当两个电梯同时都要向换乘楼层前进时,先占据换乘楼层的电梯会进行换乘操作,另一个电梯会处于等待换乘的阶段。在进行换乘操作的电梯完成换乘后,会让出换乘楼层,并唤醒等待电梯。但是如果电梯抵达换乘楼层并不是进行换乘操作,只是接取换乘楼层的请求时,如果其将换乘楼层占领,另一个电梯如也想进入换乘楼层会进入等待,但是在换乘楼层的电梯在接取请求后不会将其唤醒,从而使等待电梯一直等待。因此需要在换乘楼层空出后,唤醒需要进入换乘楼层的电梯。

总结

稳定内容

任务目标

毫无疑问,每个作业的任务目标都是将所有的乘客送到目标楼层。其中一个核心内容就是乘客请求,这是我们需要处理的任务。在这三次作业中,除了第一次作业指定了运送电梯外(第一次作业的指定电梯更多是关于分配策略的变化),三次作业中乘客请求的主体内容是没有变化的,核心就是起始楼层与目标楼层,我们所需要完成的任务也都是将乘客从起始楼层运送到目标楼层。

变化内容

结束条件

第一次作业的线程结束条件很简单,就是看共享的请求队列是否为空

但是第二次作业加入了reset请求,使得结束条件的判断更为复杂,不仅仅需要考虑总请求队列,还要考虑尚未加入到总请求队列中的重置请求。

第三次作业加入了双轿厢电梯,带来的改变是换乘请求。如果换乘请求没有处理完,相应的电梯线程也不能进入结束阶段

分配策略(调度器的变化)

第一次作业指定了运送的电梯,因此分配策略无需考虑

但是在第二次作业中不在指定运送电梯,因此需要我们自己设计分配策略

第三次作业中又加入了双轿厢电梯,因此分配策略需要做出相应的变化。调度器也从单层变为了双层。

重置请求(电梯的变化)

第一次作业没有这个任务啊

第二次作业新增reset请求,带来了电梯属性的变化与重置请求的处理

第三次作业新增DoubleCarReset请求,带来了新的电梯种类,换乘请求的处理还有双轿厢电梯的运行策略

心得体会

线程安全

多线程程序最关键的一个问题就是线程安全,这也是导致我在编写程序中抓狂,最后程序出现问题的最主要原因。

在我看来,线程安全就是想要达到如果多个线程访问一个共享对象时,可以保证调用这个对象的行为都可以获得正确的结果。

为了达成这个目的,使用了两种方法,一种是synchronized关键字来对方法和代码块进行同步保护,另一种是使用了 wait()notifyAll() 方法来进行线程间的等待和唤醒。(也要注意使用顺序等问题避免死锁的产生)

层次化设计

在这三次作业中,层次化设计也十分的重要

一个是在类的设计上,通过Input类,Schedule类和Elevator类相互协作来完成任务。

另一个是在方法设计上。将分配策略相关的方法,重置处理的方法,电梯运行等方法都进行拆解。使得线程类的run方法中只保留最基本的操作,使得结构更加清晰

碎碎念

第二单元的作业相比第一单元来说,代码量有所下降,但是思维难度有所上升,主要是第一次接触多线程程序的编写,一开始没有能够理清楚各个线程的关系,包括该把哪些类设置为线程类,什么应该作为共享对象等等这些问题,但在对任务进行细致的分析后也还是能够逐渐的搞明白应该怎么去设计,也对多线程有了更加深刻的理解。

但是对于这单元的作业也还是有着一些想要达到却未能尝试的地方,一个是尝试影子电梯的分配策略,一个是在使用synchronized关键字外尝试使用ReentrantLockReentrantLock更加的灵活,在处理某些同步问题时可能更有优势。主要也是因为时间问题,加上担忧引入新的问题而难以解决,我没有能够做到这些实现,也是有点小小的遗憾。

OO课到这里已经快走完一半了,也是在“攀爬昆仑”的过程中学到了许多,也希望能够在接下来的课程中继续加油!

...全文
40 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
内容概要:本文研究了基于QLearning自适应强化学习的PID控制器在自主水下航行器(AUV)中的应用,通过Matlab代码实现了对水下机器人的动力学建模与运动控制。重点探讨了将强化学习算法QLearning与传统PID控制相结合的方法,以提升AUV在复杂、时变及非线性水下环境中的自适应控制能力。文中系统分析了AUV的运动学与动力学特性,阐述了传统PID参数整定面临的挑战,并提出采用QLearning算法在线动态优化PID控制器的比例、积分和微分参数,从而实现对系统误差、响应速度、超调量等性能指标的综合优化。通过Matlab仿真实验验证了该复合控制策略在轨迹跟踪精度、抗外部干扰能力和系统鲁棒性方面的显著优势,充分展示了强化学习在智能水下装备自主控制领域的可行性和应用潜力。; 适合人群:具备自动控制理论基础、强化学习基础知识及Matlab编程能力的研究生、科研人员和自动化、海洋工程、机器人等相关领域的技术研发人员。; 使用场景及目标:①用于水下机器人、无人潜航器等智能移动装备的高精度运动控制系统设计与开发;②开展强化学习与经典控制理论融合创新的教学案例与科学研究;③解决传统固定参数PID控制器在面对模型不确定性和环境扰动时适应性差、控制性能下降的关键问题。; 阅读建议:建议读者结合提供的Matlab代码进行仿真实践,重点关注QLearning算法中状态空间、动作空间的设计逻辑以及奖励函数的构建原则,深入理解其在参数寻优过程中的作用机制,并可通过调整环境参数和初始条件来测试算法的鲁棒性与泛化能力。
内容概要:本文以有源中点箝位(ANPC)三电平并网逆变器为研究对象,提出并构建了一套融合双极性倍频脉宽调制(DPWMA)、正负序分离锁相控制与电网电压前馈的一体化高性能并网控制策略。通过深入分析ANPC三电平拓扑在开关损耗均衡、中点电位可控性及输出谐波低等方面的结构优势,确立了其作为大功率高质量并网系统的硬件基础。在此基础上,DPWMA调制策略有效提升等效开关频率,显著降低输出电流电压的总谐波畸变率,优化稳态电能质量;正负序分离锁相技术精准剥离电网电压中的负序扰动分量,保障电网不平衡工况下的相位同步精度与并网电流对称性;电网电压前馈控制则通过前瞻性补偿机制,突破传统闭环控制的响应滞后瓶颈,大幅提升系统在电压骤变、畸变等动态扰动下的抗扰能力与动态响应速度。研究通过搭建完整的Simulink仿真模型,在稳态对称、电网不平衡及动态切换等多种工况下进行全面验证,结果表明该复合控制策略在电能质量、运行稳定性与工况适应性方面均具有显著优越性。; 适合人群:具备电力电子、自动控制或新能源并网等相关专业背景,从事科研、工程开发或处于研究生及以上学习阶段的专业技术人员。; 使用场景及目标:①应用于光伏发电、风力发电等新能源系统的大功率并网逆变器高性能控制设计;②解决电网电压不平衡、畸变等复杂非理想工况下的并网稳定性与电能质量问题;③提升工业级并网设备的动态响应速度与运行可靠性;④为相关领域的仿真建模、控制算法开发与性能优化提供系统性的技术参考与实现方案。; 阅读建议:建议结合文中所述的Simulink仿真模型进行实践操作,重点深入理解DPWMA调制的具体实现逻辑、正负序分离锁相环的设计原理以及前馈-反馈复合控制结构的集成方法,通过设置不同工况的对比仿真实验,直观体会各项关键技术对系统整体性能的提升作用。

301

社区成员

发帖
与我相关
我的任务
社区描述
2023年北航面向对象设计与构造
学习 高校
社区管理员
  • YannaZhang
  • CajZella
  • C_ecelia
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧