You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang Goroutine随机无报错停止问题求助

问题分析与修复方案

核心问题点

  1. 泵状态未重置:处理完车辆加油后,未将pump.IsOccupied设为false,导致泵永久处于「占用」状态,后续循环的if pump.IsOccupied == false条件永远不满足,goroutine不再进入处理逻辑,表现为停止响应。
  2. 锁逻辑错误:
    • 在select的case分支中,持有Mutex的情况下执行time.Sleep,无意义地阻塞其他可能访问该泵的操作。
    • 解锁逻辑不一致:仅default分支有提前解锁,case分支需到if块结束才解锁,易引发锁占用问题。
  3. 竞态条件:对pump.IsOccupied的读写未通过Mutex同步,可能导致goroutine读取到旧状态,引发逻辑异常。
  4. 流程未闭环:加油完成后,未将车辆传递到后续的registerQueues,也未清理pump.CurrentCar,导致泵状态无法恢复。

修复后的代码

func pumpOperation(pump *Pump, pumpQueue *EntryQueue, registerQueues *[]*RegisterQueue, outputs *[]Car, maxCarCount int64, wg *sync.WaitGroup) {
    defer wg.Done()

    // 初始化随机数种子,避免多个goroutine生成重复随机值
    rand.Seed(time.Now().UnixNano() + int64(rand.Intn(1000)))

    for {
        // 加锁检查泵的可用状态,避免竞态
        pump.Mutex.Lock()
        isFree := !pump.IsOccupied && strings.Compare(pump.Type, pumpQueue.Type) == 0
        pump.Mutex.Unlock()

        if !isFree {
            time.Sleep(1 * time.Millisecond)
            continue
        }

        pump.Mutex.Lock()
        // 双重检查:防止解锁到重新加锁的间隙被其他goroutine占用
        if pump.IsOccupied || strings.Compare(pump.Type, pumpQueue.Type) != 0 {
            pump.Mutex.Unlock()
            continue
        }

        select {
        case car := <-pumpQueue.Queue:
            // 设置泵为占用状态后立即解锁,sleep无需持有锁
            pump.CurrentCar = car
            pump.CurrentCar.PumpEntry = time.Now()
            pump.IsOccupied = true
            pump.Mutex.Unlock()

            // 模拟加油服务时间
            serviceTime := rand.Intn(pump.ServiceMax-pump.ServiceMin+1) + pump.ServiceMin
            time.Sleep(time.Duration(serviceTime) * time.Millisecond)

            // 加油完成,重置泵状态并流转车辆
            pump.Mutex.Lock()
            pump.IsOccupied = false
            pump.CurrentCar = nil
            // 将车辆送入对应类型的登记队列(可根据实际逻辑调整)
            for _, rq := range *registerQueues {
                if strings.Compare(rq.Type, car.Type) == 0 {
                    rq.Queue <- car
                    break
                }
            }
            pump.Mutex.Unlock()

        default:
            // 无车辆等待,解锁后短暂休眠降低CPU占用
            fmt.Printf("No car in queue, %s pump waits\n", pump.Type)
            pump.Mutex.Unlock()
            time.Sleep(1 * time.Millisecond)
        }
    }
}

关键修改说明

  • 重置泵状态:加油完成后强制将pump.IsOccupied设为false,清空pump.CurrentCar,确保泵能重新接收新车辆。
  • 优化锁持有时间:仅在修改/读取泵状态的临界区持有Mutex,time.Sleep前释放锁,避免不必要的阻塞。
  • 双重检查状态:重新加锁后再次确认泵的状态,防止间隙时间被其他goroutine抢占,消除竞态风险。
  • 同步状态读写:所有对pump.IsOccupied的操作都通过Mutex保护,保证状态一致性。
  • 闭环流程:添加车辆到登记队列的逻辑,确保业务流程完整(可根据实际需求调整该部分逻辑)。

内容的提问来源于stack exchange,提问作者urula

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 03:18:15