【问题标题】:fatal error when solving deadlock error with semaphores使用信号量解决死锁错误时出现致命错误
【发布时间】:2020-12-11 02:45:29
【问题描述】:

我正在学习围棋。我正在尝试使用信号量解决 goroutine 上的死锁问题。我创建了两个写入无缓冲通道的函数。阅读正在主频道上进行。第三个功能应该关闭通道。当我运行程序时,它会抛出这个错误 致命错误:所有 goroutine 都处于休眠状态 - 死锁! 有人可以向我解释为什么这不起作用。

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup
var s = []string{"a", "b", "c", "d"}
var w = []string{"w", "x", "t", "z", "p"}

func f(c chan string, ch chan bool) {
    for _, word := range s {
        c <- word
    }
    fmt.Println("f about to exit")
    ch <- true
    wg.Done()
}
func g(c chan string, ch chan bool) {
    for _, word := range w {
        c <- word
    }
    fmt.Println("g about to exit")
    ch <- true
    wg.Done()
}
func f1(ch chan string, c chan bool) {
    <-c
    <-c
    fmt.Println("about to close channel")
    close(ch)
}

func main() {
    ch := make(chan string)
    c := make(chan bool)
    wg.Add(3)
    go f(ch, c)
    go g(ch, c)
    go f1(ch, c)
    for word := range ch {
        fmt.Println(word)
    }

    wg.Wait()
}

【问题讨论】:

    标签: go


    【解决方案1】:

    数据通道和信令通道的命名应该一致。
    就是这样。

    这里有两个生产者 goroutine 和一个消费者 goroutine,
    所以让我先简化你的代码,试试online

    func main() {
        ch := make(chan string)
        done := make(chan struct{})
        go func() {
            for _, word := range []string{"1", "2", "3"} {
                ch <- word
            }
            done <- struct{}{}
        }()
        go func() {
            for _, word := range []string{"10", "20", "30", "40"} {
                ch <- word
            }
            done <- struct{}{}
        }()
        go func() {
            <-done
            <-done
            close(ch)
        }()
        for word := range ch {
            fmt.Print(word, " ")
        }
        fmt.Println()
    }
    

    输出:

    1 2 10 3 20 30 40 
    

    注意事项:

    1. 您不需要sync.WaitGroup,因为已完成的频道足以发送信号。
    2. 空结构足以发出信号。
    3. 在收到两个done信号后,可以关闭数据通道,这样main就退出循环了。

    【讨论】:

      【解决方案2】:

      启动三个 goroutine 后,您从通道 ch 读取直到 ch 关闭。所有函数都将ch 作为它们写入的第一个参数,但f1 正在写入它的第二个参数,而不是第一个参数。也就是说,f1 正在写入主通道c,所以f1 在第一次写入时被阻塞,因为没有人从c 读取。主 goroutine 被阻止从 ch 读取,因为在完成 fg 之后,没有人写入它。

      这看起来像是频道命名混乱:两个函数得到(c, ch),一个得到(ch, c),但都用(ch, c) 调用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-11-01
        • 2021-03-27
        • 2021-05-09
        • 2012-08-28
        • 1970-01-01
        • 2012-08-08
        • 1970-01-01
        相关资源
        最近更新 更多