309
社区成员
发帖
与我相关
我的任务
分享在三次作业中,我主要使用 synchronized 和 wait/notifyAll 来保证线程安全。
GlobalQueue 是输入线程和调度器之间的共享队列。InputThread 负责读取请求,然后把请求放进 GlobalQueue;Dispatcher 再从 GlobalQueue 中取出请求并分配给电梯。所以 GlobalQueue 中的加入请求、取出请求、判断是否为空等操作都需要同步,避免多个线程同时访问导致数据错误。
在 CabinThread 中,每个电梯线程都有自己的锁,用来保护电梯内部的任务队列、乘客列表、当前楼层、运行方向和特殊请求状态。调度器给电梯分配任务时,会把任务加入电梯内部队列;电梯线程自己再从队列中取任务执行。如果这些操作不同步,就可能出现请求丢失或重复处理的问题。
hw3加入双轿厢后,我在 ShaftController 中额外处理同一井道内两个轿厢的安全问题。主轿厢和备用轿厢不能出现在同一楼层,也不能发生越界冲突,所以移动前必须检查另一部轿厢的位置。
锁不是越多越好,同步块也不是越大越好。同步块中应该只放必要的共享变量修改和判断,比如队列入队、出队、状态切换、线程等待和唤醒。像电梯移动、开关门、休眠这些耗时操作,最好放在同步块外面,否则容易导致其他线程长时间拿不到锁,影响性能甚至造成超时。
我的调度器主要由 Dispatcher 实现。它的作用是从 GlobalQueue 中取出请求,然后根据当前电梯状态,把请求分配给合适的 CabinThread。
hw1中,调度器比较简单,主要负责把乘客请求交给对应电梯。
hw2加入维修后,Dispatcher 需要判断电梯是否还能继续接任务。如果某个电梯要维修,就不能继续给它分配普通乘客请求。同时,维修过程中被打断的乘客还需要重新调度。
hw3加入改造、回收和双轿厢后,调度器的逻辑更复杂。Dispatcher 不仅要选择电梯,还要判断请求能不能直达。如果不能直达,就需要结合 `ShaftController` 和换乘楼层,把任务拆成不同阶段处理。
整体线程交互关系是:
InputThread 负责读取输入,GlobalQueue 负责保存请求,Dispatcher 负责分配请求,CabinThread 负责真正执行电梯动作,ShaftController 负责管理井道和双轿厢安全。
这样分层之后,每个类的职责比较清楚,后面增加维修、改造、回收功能时,也不需要把所有代码推倒重写。
调度策略整体原则为先保证正确性,再尽量优化性能。
在普通电梯阶段,我主要按照距离和方向选择电梯。离乘客出发楼层更近、方向更合适、任务更少的电梯会优先被选择。
在 ·CabinThread· 内部,电梯会优先处理已经在电梯内的乘客。如果电梯内没人,就去接最近的等待乘客。这样可以减少空跑。
在hw3中,双轿厢有服务范围限制。主轿厢和备用轿厢负责的楼层不同,所以 ·Dispatcher· 需要先判断请求属于哪个区域,再分配给合适的轿厢。如果请求跨区域,就需要在换乘楼层处理。
对于时间性能,主要通过选择较近、顺路的电梯来减少等待时间。对于电量性能,尽量减少无意义移动、频繁反向和不必要的开关门。对于特殊请求,优先保证维修、改造、回收流程正确完成。我觉得自己的策略不是最优的,但比较稳。
第二单元里我遇到最多的问题就是多线程 bug,尤其是在 hw6 和 hw7 中。
hw6 中,我经常遇到的问题是维修流程处理不完整。有时电梯进入维修后,里面的乘客处理了,但是已经 ·RECEIVE· 还没上车的乘客没有重新分配,导致程序最后一直认为还有任务没完成。这个问题表面上看起来是超时,其实是某个请求的生命周期没有结束。
hw7 中,我遇到的问题更多。因为加入了双轿厢、改造和回收,状态变得很复杂。我曾经在强测中只通过了少数测试点,很多错误都是TLE。一开始我以为是调度策略太慢,后来发现很多时候不是性能问题,而是线程卡住了,或者某些乘客没有被正确完成。
通过三次作业,我对线程安全的理解是:不是简单地多加锁,而是要知道哪些数据是共享的、谁负责修改它、什么时候需要通知其他线程。比如 GlobalQueue 只负责请求的保存和取出,Dispatcher 只负责调度,CabinThread 只负责执行电梯动作,ShaftController 只负责井道和双轿厢安全。每个类只管理自己的状态,程序就会更清楚,也更不容易出错。
我主要是用于分析bug、整理状态机、检查多线程问题、给出修改思路和帮助写总结。尤其在hw6和hw7报错的时候时使用大模型寻找bug的频率增加了很多。
第二单元的作业让我感到非常折磨,尤其是hw6时不是在修bug的过程就是在找bug的过程上。但收获也很大。它让我第一次真正感受到面向对象设计和多线程编程的难度,也让我明白一个清晰的架构比后期不断打补丁更重要。