duanbinren8906 2018-02-19 11:48
浏览 14
已采纳

解决goroutines死锁

I've been trying to solve this simple problem I encountered in Golang concurrency. I've been searching all possible solutions, but found nothing specific to my problem(or I might be missed one). Here's my code:

package main

import (
    "fmt"
    "time"
)

func producer(ch chan int, d time.Duration, num int) {

    for i:=0; i<num; i++ {
        ch <- i
        time.Sleep(d)
    }
}

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

    go producer(ch, 100*time.Millisecond, 2)
    go producer(ch, 200*time.Millisecond, 5)

    for {
        fmt.Println(<-ch)    
    }

    close(ch)
}

It prints error:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]: main.main() D:/Code/go/src/testconcurrency/main.go:23 +0xca exit status 2

What is the efficient way to avoid this error?, Thank you.

  • 写回答

5条回答 默认 最新

  • doubingjian2006 2018-02-20 06:50
    关注

    You need to synchronize all the asynchronous process in your goroutines. Your main thread and the goroutine threads are not synchronous process. Your main thread will never knew when to stop invoking channel from goroutines. Since your main thread loop over the channel, it always invoke the value from channel, and when the goroutines finished and the channel stop sending value, your main thread cannot get anymore value from the channel, hence the condition become deadlock. To avoid this use sync.WaitGroup to synchronize the asynchronous process.

    Here's the code:

    package main
    
    import (
        "fmt"
        "time"
        "sync"
    )
    
    func producer(ch chan int, d time.Duration, num int, wg *sync.WaitGroup) {
        for i:=0; i<num; i++ {
            ch <- i;
            time.Sleep(d);
        }
        defer wg.Done();
    }
    
    func main() {
        wg  := &sync.WaitGroup{}
        ch  := make(chan int);
    
        wg.Add(2);
        go producer(ch, 100*time.Millisecond, 2, wg);
        go producer(ch, 200*time.Millisecond, 5, wg);
    
        go func() {   
        wg.Wait()
        close(ch)
        }()
    
        // print the outputs
        for i:= range ch {
            fmt.Println(i);
        }
    }
    

    https://play.golang.org/p/euMTGTIs83g

    Hope it helps.

    Since my solution looks a little similar to already answered, I change it to my original answer before modification to suit OP question.

    Here's the code:

    package main
    
    import (
        "fmt"
        "time"
        "sync"
    )
    
    // producer produce values tobe sent to consumer
    func producer(ch chan int, d time.Duration, num int, wg *sync.WaitGroup) {
        defer wg.Done();
        for i:=0; i<num; i++ {
            ch <- i;
            time.Sleep(d);
        }
    }
    
    // consumer consume all values from producers
    func consumer(ch chan int, out chan int, wg *sync.WaitGroup) {
        defer wg.Done();
        for i:= range ch {
            out <- i
        }
    }
    
    // synchronizer synchronize all goroutines to avoid deadlocks
    func synchronizer(ch chan int, out chan int, wgp *sync.WaitGroup, wgc *sync.WaitGroup) {
        wgp.Wait()
        close(ch)
        wgc.Wait()
        close(out)
    }
    
    func main() {
        wgp  := &sync.WaitGroup{}
        wgc  := &sync.WaitGroup{}
        ch  := make(chan int);
        out := make(chan int);
    
        wgp.Add(2);
        go producer(ch, 100*time.Millisecond, 2, wgp);
        go producer(ch, 200*time.Millisecond, 5, wgp);
    
        wgc.Add(1);
        go consumer(ch, out, wgc)
    
        go synchronizer(ch, out, wgp, wgc)
    
        // print the outputs
        for i:= range out {
            fmt.Println(i);
        }
    }
    

    Using consumer goroutine to fan-in all input from multiple goroutines and read all values from the consumer goroutine.

    Hope it helps.

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

报告相同问题?

悬赏问题

  • ¥15 slam rangenet++配置
  • ¥15 对于相关问题的求解与代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 信号傅里叶变换在matlab上遇到的小问题请求帮助
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作
  • ¥15 求NPF226060磁芯的详细资料
  • ¥15 使用R语言marginaleffects包进行边际效应图绘制
  • ¥20 usb设备兼容性问题
  • ¥15 错误(10048): “调用exui内部功能”库命令的参数“参数4”不能接受空数据。怎么解决啊