首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么我的代码死锁以及如何修复它

为什么我的代码死锁以及如何修复它
EN

Stack Overflow用户
提问于 2018-08-31 07:16:21
回答 3查看 73关注 0票数 3

为什么我的代码在从通道读取时死锁(然后崩溃),我希望它在通道完全读取后在读取时阻塞,但不会崩溃。我知道这是一种死锁状态,因为没有人在通道上写入和读取数据块。

如何更改代码以读取所有频道内容,然后从main退出,而不是crash。

Go游乐场:https://play.golang.org/p/rjXZZOx1FFZ

代码语言:javascript
复制
package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    news := make(chan int, 10)

    wg.Add(1)

    go foo(&wg, news) 

    wg.Wait()   

    for {
        fmt.Printf("reading: %v\n", <-news) 
        //crashes here after printing 0-9
    }

}

func foo(wg *sync.WaitGroup, news chan int) {
    for i:=0; i<10;i++ {
        fmt.Printf("Writing\n")
        news <- i
    }
    (*wg).Done()
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-08-31 07:28:53

程序死锁,因为通道上的主块接收,并且没有其他goroutines将发送到该通道。

使用这种方法读取所有通道内容,然后从main退出:main读取通道直到关闭;foo写入所有值并关闭通道。

代码语言:javascript
复制
func main() {
    news := make(chan int, 10)
    go foo(news)
    // range breaks when the channel is closed
    for v := range news { 

        fmt.Printf("reading: %v\n", v)
    }

}

func foo(news chan int) {
    for i := 0; i < 10; i++ {
        fmt.Printf("Writing\n")
        news <- i
    }
    // close channel to indicate that no more values will be sent.
    close(news) 
}

Run it on the Playground

票数 2
EN

Stack Overflow用户

发布于 2018-08-31 07:41:16

要解释为什么会发生这种情况,你会从死机中得到的错误消息告诉你它的要点:

代码语言:javascript
复制
fatal error: all goroutines are asleep - deadlock!

你不能让你所有的goroutine等待其他goroutine去做某件事。在这种情况下,当运行foo的goroutine完成,并且运行main的goroutine已经接收到发送到news通道的所有消息(0到9)时,您的程序只剩下一个goroutine等待在一个通道上接收消息,这个通道再也不会有消息发送给它了,因为没有其他goroutine可以这样做。

票数 2
EN

Stack Overflow用户

发布于 2018-08-31 07:55:03

代码因死锁而崩溃。

fatal error: all goroutines are asleep - deadlock!

您在原始代码中遇到了一些有趣的问题。

如果您关闭了foo goroutine中的新闻频道,而不是死锁,那么您将永远在main中运行无限循环。

2简单的代码更改应该会使这一点变得更清楚,并将导致它在处理news项后退出。

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

代码语言:javascript
复制
package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    news := make(chan int, 10)

    wg.Add(1)

    go foo(&wg, news)

    wg.Wait()

    for n := range news {
        fmt.Printf("reading: %v\n", n)
    }
    fmt.Println("We're out of news!")
}

func foo(wg *sync.WaitGroup, news chan int) {
    for i := 0; i < 10; i++ {
        fmt.Printf("Writing\n")
        news <- i
    }
    close(news)
    wg.Done()
}

当然,您可以不使用WaitGroups重写它,而只是像其他人指出的那样使用通道,这可能是一个更优雅的解决方案。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52106572

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档