dongtuo3370 2016-01-04 02:29
浏览 22
已采纳

发生致命错误:所有goroutine都在睡眠中-死锁! 一个简单的测试方案

I am trying to repro an issue and came to a minimum use case with the following code. If I close all the channels (bypassing the i == 0 test), things are working as expected. Wg state decrements and done is triggered, main exits fine. When I skip closing one of these channel (on purpose), I expect the main routine to wait while the waitgroup semaphore will block indefinitely in this case. Instead, I am getting an error: "fatal error: all goroutines are asleep - deadlock!". Why is that? I must have missed something fundamental or this the runtime being overzealous?

package main

import (
    "fmt"
    "sync"
)

const N int = 4

func main() {

    done := make(chan struct{})
    defer close(done)

    fmt.Println("Beginning...")

    chans := make([]chan int, N)
    var wg sync.WaitGroup

    for i := 0; i < N; i++ {
        wg.Add(1)
        chans[i] = make(chan int)
        go func(i int) { // p0
            defer wg.Done()
            for m := range chans[i] {
                fmt.Println("Received ", m)
            }
            fmt.Println("Ending p", i)
        }(i)
    }

    go func() {
        wg.Wait()
        done <- struct{}{} // signal main that we are done
    }()

    for i := 0; i < N; i++ {
        fmt.Println("Closing c", i)
        if i != 0 { // Skip #0 so wg doesn't reach '0'
            close(chans[i])
        }
    }

    <-done // wait to receive signal from anonymous join function
    fmt.Println("Ending.")
}

UPDATE: I edited the code to avoid the race condition. Still getting this error.

The if i != 0 is there because it's intentional. I want the wg.Wait to block forever (with its semaphore never reaching 0.) Why can't I do that? It seems the same as if I were using <-done without a matching done <- struct{}{} somewhere else. Would the compiler complain too in that case?

  • 写回答

2条回答 默认 最新

  • dongzheng7165 2016-01-04 02:45
    关注

    Here's what's going on:

    • The first go func(i int) { goroutine does not exit because chans[0] is not closed.
    • Because the goroutine does not exit, wg.Done is not called.
    • The call to wg.Wait() blocks forever because of the previous point.
    • Main blocks forever because the signal is not sent to done.

    You can fix the deadlock by removing the if i != 0 {, but there is another issue. There is a race on the wait group. It's possible that wg.Done() is called before wg.Add(1) is called. Call wg.Add() before starting the goroutine to avoid the race.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 spss统计中二分类变量和有序变量的相关性分析可以用kendall相关分析吗?
  • ¥15 拟通过pc下指令到安卓系统,如果追求响应速度,尽可能无延迟,是不是用安卓模拟器会优于实体的安卓手机?如果是,可以快多少毫秒?
  • ¥20 神经网络Sequential name=sequential, built=False
  • ¥16 Qphython 用xlrd读取excel报错
  • ¥15 单片机学习顺序问题!!
  • ¥15 ikuai客户端多拨vpn,重启总是有个别重拨不上
  • ¥20 关于#anlogic#sdram#的问题,如何解决?(关键词-performance)
  • ¥15 相敏解调 matlab
  • ¥15 求lingo代码和思路
  • ¥15 公交车和无人机协同运输