301
社区成员
发帖
与我相关
我的任务
分享完成乘客请求,即对于每个乘客请求(起点层,终点层),需要调度电梯将其完成,并将必要的运行信息通过输出接口进行输出。具体而言,你需要控制电梯上下行,开关门的动作以及控制乘客进出电梯来将乘客从起点层运送到终点层。我们的电梯系统有多部电梯,你需要合理的调度这些电梯来达到更好的性能(第一次作业指定了接送乘客的电梯)。

这次的作业由Main线程启动各线程,输入线程从输入读入请求,放入总请求队列,在检测到输入结束后,就将总请求队列setEnd,而调度器线程从总请求队列拿请求分配给电梯,当总请求队列空且结束时,就将每个电梯的侯乘表setEnd,结束调度器线程,电梯线程接收到请求后开始运作,当电梯没人且侯乘表空且结束时,结束电梯线程。
当总请求队列没结束但是空时,我们需要wait,锁住的是总请求队列,当setEnd或addRequest时notifyAll。
在电梯线程中当电梯没有请求但是侯乘表没有结束时,需要wait,锁住的是侯乘表,当往侯乘表加东西或setEnd时notify。
这次作业指定了电梯,所以不需要调度,但是最好这次作业就有这个类,通过请求里的电梯id来分配电梯,这样后面的作业好扩展。
在这一个单元中,都用的是同一种策略,就是look策略。
简单来说就是看电梯运行方向上有无请求,如果有就继续沿方向走,同时运行时如果可稍带就捎带上,如果方向上没有请求了,就掉转方向。
具体实现我是有一个策略类,里面有一个方法为nextDirection,返回的有三种值,如果是1就是沿原方向移动,是0就开门放人或进人,如果是-1就调转方向,而电梯里有策略这个对象,调用这个方法来给电梯发出命令。
本次作业要求简单,无bug
完成乘客请求,即对于每个乘客请求(起点层,终点层),需要调度电梯将其完成,并将必要的运行信息通过输出接口进行输出。具体而言,你需要控制电梯上下行,开关门的动作以及控制乘客进出电梯来将乘客从起点层运送到终点层。我们的电梯系统有多部电梯,你需要合理的调度这些电梯来达到更好的性能。本次及以后作业不再指定电梯,同学们需设计调度器分配电梯完成乘客请求!!!
电梯在运行一段时间以后,其性能参数(
满载人数、移动时间)可能会发生改变。接收到重置指令的电梯需要尽快停靠后完成重置动作,再投入电梯系统运行。为安全起见,电梯重置时内部不可以有乘客,且重置动作需要时间T_{reset}=1.2sTreset=1.2s。为避免出现多部电梯接送同一乘客造成资源浪费的情况,引入RECEIVE约束。同时我们希望同学们将
RECEIVE作为调度器的附加输出来说明自己的分配方案,边界情况见正确性说明。

这次作业较上次多了电梯线程向总请求队列加请求,所以总请求队列这次被输入、调度器、电梯三个线程共享,而因为这次作业不指定电梯,所以调度器里会有电梯列表从而根据电梯的状态来调度。并且这次调度器结束的条件为电梯里什么请求也没有且总请求队列结束且空。
这次在调度器中判断总请求结束且空,但是电梯里还有东西时,调度器就需要wait,因为电梯里的请求有可能会回到调度器,所以为了避免轮询,所以加了wait,锁的是总请求队列,当电梯往总请求队列加东西或电梯处理完请求准备wait时来唤醒。
本次调度采取的是首先淘汰超载的电梯,这里超载指的是电梯里的人加侯乘表的人加上缓冲队列的人,这里缓冲队列指的是电梯在reset是接收到的请求,如果都是超载的,那么选出一个超载最少的电梯,如果有不超载的,那么再淘汰不能捎带的,如果都不能捎带,那么选一个离得最近的,这里离得最近指的是电梯从当前楼层出发到能捎带这个请求需要走的距离,如果有可以捎带的,那么在捎带的当中选一个离得最近的。这么调度强测过后效果很不错。
本次作业bug比较多,首先说一下我强测中的bug,我强测中因为超时互测错了几个点,检查后发现检测超载时没有加上缓冲队列的请求,导致最后我的电梯只有一个在运作。其次还有就是在电梯线程里处理完请求后要唤醒调度器,调度器被唤醒后要给每个电梯的侯乘表setEnd,但是有可能在setEnd完后,有一个电梯才进入wait,正确应该是加锁,但我在进wait前又判断了是否是end,不是end才能进入wait,这样还是有风险,但是触发几率太小,也就没再改了。还有一个可能的bug就是在reset的时候输出Receive,这是因为在判断电梯是否是reset时,电梯可能已经进入reset方法但还没将reset置为true,所以判断不是reset后就输出了Receive,所以解决方法就是在调度器识别出是reset请求后就早早的将对应电梯的reset置为true,这样就会避免这个问题。
这次作业新增了第二类重置请求,第二类重置请求将电梯修改为双轿厢电梯,重置参数包含需要重置的电梯ID,换乘楼层,两个轿厢的相关参数(移动一层的时间和满载人数)相同。当重置完成后,轿厢 A 默认初始在换乘楼层的下面一层,轿厢B默认初始换乘楼层的上面一层。(本次新增)

这次作业多了个双轿厢电梯类,它也会中途下人,所以也需要将请求加入回总请求队列。多了个IsFree类,它是用来判断换乘楼层是否是空闲的,这在后面会说到。
这次主要加的锁是为了解决双轿厢冲突问题。首先原先策略类的哪个方法多了一个返回值2,在原先方法所有返回1的前面多了一个判断,如果此时电梯要往换乘楼层移动,那么返回2,如果返回2,那么就上锁,锁的是双轿厢电梯的一个共享对象dcLock,具体代码如下:
synchronized (dcLock) {
while (!isFree.getCan()) {
try {
dcLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
isFree.setCan(false);
}
go(direction);
当换乘楼层不空闲时,就要wait,当被唤醒后,就将isfree置为false,意思是换乘楼层要不空闲了,再进入换乘楼层。唤醒的条件是要从换乘楼层移动时,先将isfree置为true,意思是换乘楼层要空闲了,再notify。还有就是如果电梯要在换乘楼层等待时,让电梯先移动离开换乘楼层,再同上唤醒,再去等待。
本次作业写的比较慢,一直都在调bug,所以没怎么写调度,最后交上去的时候是均分调度,性能分比较差,现在想一想如果有时间的话调度策略应该跟第二次作业差不多。
这次作业可能出现的bug就是双轿厢可能冲突,还有我遇到的问题是,当双轿厢电梯中途下人后,调度器提前结束了,最后发现是中途下人时是先下人,再往总请求队列加人,这样做就会在加人之前调度器误以为都是空从而结束,所以这种类似的操作都是先加后减,才会避免这样的问题。
这一单元终于过去了,真是不容易,主要是因为多线程不好找bug,连调试都调试不了,只能通过在一些地方加输出来找问题,比如轮询的时候在线程的while处加输出,看是哪个线程没结束,有一些问题有时候还不能复现,所以这一单元的调bug真是折磨人。线程安全问题还需要我们去综合考虑很多情况,看多个线程并发执行时有可能会出现什么问题,在需要同步的地方加上锁来解决问题。所以这一单元还是要多学习一些多线程和锁的知识,不然写出来的程序真是bug多。
总的来说,经过这一单元的学习,我也对多线程有了更深的了解,也对于程序中可能出现的bug有了解决的能力,希望以后能有更大的进步吧,也希望后面两个单元能轻松些。