309
社区成员
发帖
与我相关
我的任务
分享在电梯系统的多线程实现中,锁和同步块是非常关键的部分。为了保证线程安全,避免数据竞争和资源冲突,我使用了多种锁的机制来管理共享资源。
ReentrantReadWriteLock 被用于 RequestQueue 和 RequestTable 类中,这使得读操作可以并发执行,而写操作会加锁,保证了在写入数据时不会发生竞争。ElevatorThread 类中,通过使用 synchronized 关键字对一些关键方法进行同步处理,保证了线程在对电梯状态进行修改时,不会发生资源争夺。例如,move() 方法使用了 synchronized(lock) 来防止在双轿厢模式下两部电梯同时进入 F2 层导致冲突。调度器 (Schedule) 的任务是管理乘客请求并调度电梯线程执行相应的任务。调度器与电梯线程通过共享资源(如 RequestTable, RequestQueue, Shaft)进行交互。
共享资源与线程同步:多个电梯线程和调度器线程需要共享和更新请求数据,所有涉及请求的修改都需要加锁以防止并发冲突。使用 ReentrantReadWriteLock 来保护数据,确保在一个线程读取共享资源时,其他线程能够安全地访问。对于写操作,线程会被阻塞直到锁释放。
调度器唤醒电梯线程:当调度器检测到有新乘客请求时,它会将请求分配给电梯并通过 elevator.wakeUp() 方法唤醒电梯线程,让电梯开始执行任务。电梯线程在完成某些任务后可能需要等待新的指令,调度器通过 notifyAll() 和 wait() 的机制来协调线程之间的等待与执行。
调度策略的核心目标是合理分配乘客请求给合适的电梯,尽量减少电梯的运行时间和能耗。
策略实现:在 Strategy 类中,根据电梯的当前状态(如 ShaftMode),电梯是否能接收新请求以及电梯是否需要进行检修或改造等情况,决定电梯的行为。电梯行为包括:是否移动、是否开门(这一点可以做一个小优化,一直到移动或者结束前再关门,这样可以避免一些不必要的开关门重复)、是否等待等。
调度策略:调度策略costFunc通过检查ElevatorThread当前的负载、目标方向、当前请求的楼层等信息来判断最合适的电梯。比如,若电梯未满载且在合适的方向,系统会优先让电梯继续运行以接载更多乘客。
策略与任务优先级:调度策略costFunc优先处理顺路的请求,避免不必要的回头。系统会计算电梯的“成本cost”,例如路径惩罚、忙碌惩罚和负载惩罚,来决定哪部电梯最适合接载当前乘客。
调度策略不仅要考虑电梯的运行时间,还需要适应多个性能指标(如能耗、完成时间等)。这一点主要通过CostFunc来实现。
强测与互测均无bug,但是本地测试的过程及其之痛苦,总共提交了11次hh
强测无bug,互测2个bug
receivecost给电梯派活,如果电梯此时不能派活,就把cost赋值为MAX_VALUE;找到电梯cost的最小值,如果有相同的,就随机选一个;这样的机制无法应对全部cost均为MAX_VALUE的情况。强测和互测
shaft里输出begin再在elevatorThread里clearQueue就可以了。这个是随机触发的bug,本地高概率再现。elevatorThread里的curFloor的get方法加上同步,在Shaft里endMaint/Repair/Recylce之后除了notifyAll()唤醒shaft,也要唤醒主副电梯wakeUp,保证线程的安全结束。Rec_Accept状态下也保证互斥(原来只保证double状态下互斥)。从复杂的综合测试数据中提炼出导致bug的点,再根据点定位相关代码。
绝大部分原因都出在ElevatorThread或者Schedule上。
还有就是程序EndFlag的设置,保证程序的正常结束,别的倒是很少出问题。
从多线程程序的角度来看,线程安全和层次化设计是至关重要的。在本单元作业中,我的电梯系统采用了明确的层次化设计,每一部分都有明确的责任和操作流程:
RequestTable 使用了读写锁,确保多个电梯线程可以并发读取请求,而不会干扰写入操作。RequestTable 和 RequestQueue 等数据结构负责共享数据的管理。这种层次化的设计使得系统具备较好的扩展性和可维护性。模型名称:gpt5.4
Shaft类的设计。