所有的goroutine都睡着了-死锁

shstlldc  于 2023-05-27  发布在  Go
关注(0)|答案(4)|浏览(134)

对于我的一个需求,我必须创建N个工作者例程,这些例程将由一个监视例程监视。当所有工作例程完成时,监视例程必须结束。我的代码以死锁结尾,请帮助。

import "fmt"
import "sync"
import "strconv"

func worker(wg *sync.WaitGroup, cs chan string, i int ){
    defer wg.Done()
    cs<-"worker"+strconv.Itoa(i)    
}

func monitorWorker(wg *sync.WaitGroup, cs chan string) {
    defer wg.Done()
    for i:= range cs {
            fmt.Println(i)
     }
}
func main() {
    wg := &sync.WaitGroup{}
    cs := make(chan string)

    for i:=0;i<10;i++{
             wg.Add(1)
             go worker(wg,cs,i)
    } 

    wg.Add(1)
    go monitorWorker(wg,cs)
    wg.Wait()
}
1szpjjfi

1szpjjfi1#

您的monitorWorker永远不会死。当所有的工人都完成时,它继续等待cs。这会死锁,因为在cs上不会发送任何其他内容,因此wg永远不会达到0。一个可能的解决方法是让监视器在所有工作进程完成时关闭通道。如果for循环在main中,它将结束循环,从main返回,并结束程序。
例如:http://play.golang.org/p/nai7XtTMfr

package main

import (
    "fmt"
    "strconv"
    "sync"
)

func worker(wg *sync.WaitGroup, cs chan string, i int) {
    defer wg.Done()
    cs <- "worker" + strconv.Itoa(i)
}

func monitorWorker(wg *sync.WaitGroup, cs chan string) {
    wg.Wait()
    close(cs)
}

func main() {
    wg := &sync.WaitGroup{}
    cs := make(chan string)

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go worker(wg, cs, i)
    }

    go monitorWorker(wg, cs)

    for i := range cs {
        fmt.Println(i)

    }
}

您的程序有三个部分需要同步。首先,您的所有工作人员都需要发送数据。然后你的打印循环需要打印这些数据。然后你的main函数需要返回从而结束程序。在您的示例中,所有的worker都发送数据,所有的数据都被打印出来,但是消息永远不会发送到main,它应该正常返回。
在我的示例中,main执行打印操作,而“monitorWorker”只告诉main它何时收到了需要打印的每一段数据。这样程序就优雅地结束了,而不是死锁。
如果你坚持打印循环在另一个goroutine中,你可以这样做。但随后需要向main发送一个额外的通信,以便它返回。在下一个示例中,我使用一个通道来确保打印所有数据时的main结束。

package main

import (
    "fmt"
    "strconv"
    "sync"
)

func worker(wg *sync.WaitGroup, cs chan string, i int) {
    defer wg.Done()
    cs <- "worker" + strconv.Itoa(i)
}

func monitorWorker(wg *sync.WaitGroup, cs chan string) {
    wg.Wait()
    close(cs)
}

func printWorker(cs <-chan string, done chan<- bool) {
    for i := range cs {
        fmt.Println(i)
    }

    done <- true
}

func main() {
    wg := &sync.WaitGroup{}
    cs := make(chan string)

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go worker(wg, cs, i)
    }

    go monitorWorker(wg, cs)

    done := make(chan bool, 1)
    go printWorker(cs, done)
    <-done
}
nwlqm0z1

nwlqm0z12#

当我把频道定义从

strChan := make(chan string)

strChan := make(chan string, 1)

我能够修复这个错误

mnowg1ta

mnowg1ta3#

如果你知道消息通道接收的计数,那么你就可以简单地限制你的循环;

//c is channel
for a := 1; a <= 3; a++{
        fmt.Println(<-c)
}

您也可以将另一个通道(worker的状态)传递给worker,然后有条件地停止导致死锁的循环。
附言:这只是一个额外的快速解决方案。没有专门针对您的解决方案。

efzxgjgh

efzxgjgh4#

也可以这样,它会工作

import "fmt"
import "sync"
import "strconv"

func worker(wg *sync.WaitGroup, cs chan string, i int) {
    defer wg.Done()
    cs <- "worker" + strconv.Itoa(i)

}

func monitorWorker(wg *sync.WaitGroup, cs chan string) {
    defer wg.Done()
    for i := range cs {
        fmt.Println(i)
    }
}
func main() {
    wg := &sync.WaitGroup{}

    cs := make(chan string, 10)

  go monitorWorker(wg, cs)
  
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go worker(wg, cs, i)
    }
    wg.Wait()
    close(cs)
}

相关问题