对于我的一个需求,我必须创建N个工人围棋 routine ,这些 routine 将由一个监视 routine 进行监视.当所有工作 routine 完成时,监控 routine 必须结束.我的代码以死锁结尾,请帮帮忙.

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()
}

推荐答案

你的班长永远不会死.当所有工人完成后,它继续等待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)

    }
}

这是对OP的第一条 comments 的回答.

您的程序有三个部分需要同步.首先,所有员工都需要发送数据.然后打印循环需要打印这些数据.然后主函数需要返回,从而结束程序.在您的示例中,所有的工作人员都会发送数据,所有的数据都会被打印出来,但消息永远不会发送到main,它应该优雅地返回.

在我的示例中,main执行打印,"monitor orWorker"只在收到需要打印的所有数据时告诉main.这样,程序就可以优雅地结束,而不会死锁.

如果您坚持将打印循环放在另一个Goroutine中,您可以这样做.但随后需要将额外的通信发送到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
}

Go相关问答推荐

如何模拟嵌入. FS?

GORM没有从 struct 创建完整的表,如何修复?

Golang使用Run()执行的命令没有返回

如何用Golang解码这个嵌套的json?

重新赋值变量时未清除动态类型-这是错误吗?

提供的client_secret与此帐户上任何关联的SetupIntent都不匹配

如何修复proxyconnect tcp:tls:第一条记录看起来不像tls握手

为什么标准库中的 IsSorted 会反向迭代切片?

如何忽略打印达到最大深度限制 go colly

Go test "-run -" 标志执行测试更快

Go Colly 如何找到请求的元素?

在 Golang 中,如何将接口作为泛型类型与 nil 进行比较?

有没有办法将 yaml node 添加到 golang 中现有的 yaml 文档中?

Golang:隐式 struct 匹配

Golang 工作池实现意外工作

Go 中 SDL Surface 的 OpenGL 纹理

go 堆栈跟踪:在某些函数调用参数或返回值之后的问题(?)标记是什么意思?

如何在gorm中处理多个查询

Go 1.18 泛型如何使用接口定义新的类型参数

如何在 Prometheus 中正确检测区域和环境信息?