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 ubuntu子系统密码忘记
  • ¥15 信号傅里叶变换在matlab上遇到的小问题请求帮助
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作
  • ¥15 求NPF226060磁芯的详细资料
  • ¥15 使用R语言marginaleffects包进行边际效应图绘制
  • ¥20 usb设备兼容性问题
  • ¥15 错误(10048): “调用exui内部功能”库命令的参数“参数4”不能接受空数据。怎么解决啊
  • ¥15 安装svn网络有问题怎么办
  • ¥15 vue2登录调用后端接口如何实现