为什么Go陷入"致命错误:所有goroutines都睡着了"

Isa*_*ell 5 channel go

以下是我的代码中的相关摘录:

func main() {
    quit := make(chan int)

    readyQueue := make(chan Proc)
    runQueue := make(chan Proc)
    waitQueue := make(chan Proc)

    procList := getInitialProcList()
    fmt.Println(procList)

    for _, proc := range(procList) {
        switch {
            case proc.Status == READY:
                readyQueue <- proc
                tick(quit, readyQueue, runQueue, waitQueue)
            case proc.Status == RUN:
                runQueue <- proc
                tick(quit, readyQueue, runQueue, waitQueue)
            case proc.Status == WAIT:
                waitQueue <- proc
                tick(quit, readyQueue, runQueue, waitQueue)
        }
    }

    <-quit // blocks to keep main thread alive
}

func tick(quit chan int, readyQueue chan Proc, runQueue chan Proc, waitQueue chan Proc) {
    select {
    case p := <-readyQueue:
        fmt.Println(p)
    default:
        fmt.Println("[tick] nothing in ready queue")
    }

    select {
    case p := <-waitQueue:
        fmt.Println(p)
    default:
        fmt.Println("[tick] nothing in wait queue")
    }

    select {
    case p := <-runQueue:
        fmt.Println(p)
    default:
        fmt.Println("[tick] nothing in run queue")
    }

    quit <- 0
}
Run Code Online (Sandbox Code Playgroud)

我不明白为什么我得到的错误fatal error: all goroutines are asleep - deadlock!就行了readyQueue <- proc在上面的代码.

jim*_*imt 14

就代码所示,您永远不会为您创建的任何频道启动并发读取器.因为它们是无缓冲的,所以对它们的任何写入都将阻塞,直到有人在某处从另一端读取.在您的代码中不是这种情况.

如果tick应该是消费者,你应该在进入循环之前将其激活.然后它应该有一个循环本身,所以它不断轮询通道的新值.

go tick(quit, readyQueue, runQueue, waitQueue)

for _, proc := range(procList) {
    ....
}
Run Code Online (Sandbox Code Playgroud)

另一个直接的解决方案是使用缓冲区1创建所有通道.

quit := make(chan int, 1)

readyQueue := make(chan Proc, 1)
runQueue := make(chan Proc, 1)
waitQueue := make(chan Proc, 1)
Run Code Online (Sandbox Code Playgroud)

虽然这将解决您的直接问题,但您的设计仍存在其他一些潜在问题.我们需要确切地知道您要完成的是什么,以便给出更全面的答案.

  • 吉姆进得太快了.另外,tick函数中的select语句不会像写入的那样工作 - 你可能需要一个select语句和一个for循环.最后,您需要在发送完毕后关闭各种频道. (2认同)