【问题标题】:Why does Go deadlock with "fatal error: all goroutines are asleep"为什么 Go 会因“致命错误:所有 goroutine 都处于睡眠状态”而死锁
【发布时间】:2014-04-22 03:03:56
【问题描述】:

这是我的代码的相关摘录:

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
}

我不明白为什么我在上面代码中的readyQueue &lt;- proc 行上收到错误fatal error: all goroutines are asleep - deadlock!

【问题讨论】:

  • 不使用 goroutine 的渠道是什么?

标签: go channel


【解决方案1】:

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

如果tick 应该是消费者,你应该在进入循环之前启动它。 然后它本身应该有一个循环,因此它会不断轮询通道以获取新值。

go tick(quit, readyQueue, runQueue, waitQueue)

for _, proc := range(procList) {
    ....
}

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

quit := make(chan int, 1)

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

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

【讨论】:

  • Jimt 进入得太快了。此外,tick func 中的 select 语句不会像所写的那样工作 - 您可能需要一个 select 语句和一个 for 循环。最后你需要在发送完成后关闭各个通道。
猜你喜欢
  • 1970-01-01
  • 2016-07-30
  • 1970-01-01
  • 2015-01-11
  • 1970-01-01
  • 1970-01-01
  • 2015-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多