为什么我的 Golang goroutine 代码会出现死锁?

huangapple go评论70阅读模式
英文:

why my golang goroutine code get deadlocked

问题

我尝试使用通道和goroutine编写一些代码,但是出现了死锁,为什么会这样呢?我在使用WaitGroup方面有什么错误吗?我感到很困惑...

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

func main() {
	chan1 := make(chan string)
	chan2 := make(chan string)
	chan3 := make(chan string, 2)
	wg.Add(1)
	go makeChanStr("yeye", chan1, chan3)
	wg.Add(1)
	go makeChanStr("okok", chan2, chan3)
	wg.Wait()
	close(chan3)
	println(<-chan1)
	println(<-chan2)
	for chs := range chan3 {
		println(chs)
	}
}

func makeChanStr(s string, c1 chan string, c2 chan string) {
	defer wg.Done()

	c1 <- "get " + s
	c2 <- "same value"
	fmt.Printf("execute ok %s", s)
}

Stackoverflow不让我提交问题......所以我只能添加一些文本.....

英文:

I try to write some goroutine with channel, but get deadlocked, why?
Am I doing wrong with WaitGroup, so confused...

package main

import (
    &quot;fmt&quot;
    &quot;sync&quot;
)

var wg sync.WaitGroup

func main() {
    chan1 := make(chan string)
    chan2 := make(chan string)
	chan3 := make(chan string, 2)
    wg.Add(1)
    go makeChanStr(&quot;yeye&quot;, chan1, chan3)
 	wg.Add(1)
	go makeChanStr(&quot;okok&quot;, chan2, chan3)
    wg.Wait()
    close(chan3)
 	println(&lt;-chan1)
    println(&lt;-chan2)
    for chs := range chan3 {
	     println(chs)
    }
}

func makeChanStr(s string, c1 chan string, c2 chan string) {
    defer wg.Done()

    c1 &lt;- &quot;get &quot; + s
	c2 &lt;- &quot;same value&quot;
	fmt.Printf(&quot;execute ok %s&quot;, s)
}

Stackoverflow just don't let me submit the question.......so I just have to add some text.....

答案1

得分: 4

主要是在wg.Wait()的代码块上,它等待这两个goroutine完成(因为有wg.Add(1)wg.Done())。

go makeChanStr("yeye", chan1, chan3)
go makeChanStr("okok", chan2, chan3)

但它们在chan1(或chan2)上阻塞,因为它是一个无缓冲通道。

chan1 := make(chan string)

尝试将chan1chan2更改为带缓冲的通道:

chan1 := make(chan string, 1)
chan2 := make(chan string, 1)
英文:

main block on wg.Wait(), which wait this two go routines to finish(because of wg.Add(1) and wg.Done())

go makeChanStr(&quot;yeye&quot;, chan1, chan3)
go makeChanStr(&quot;okok&quot;, chan2, chan3)

but they block on chan1 (or chan2) , because it's an unbuffer channel.

chan1 := make(chan string)

try change chan1 and chan2 to buffer channels:

chan1 := make(chan string,1)
chan2 := make(chan string,1)

答案2

得分: 1

这段代码在主goroutine中的wg.Wait()和工作goroutine中写入c1时会阻塞。为了避免这种情况,可以在wg.Wait()之前从c1c2中读取数据,从而解除工作goroutine的阻塞,它们将不会在写入缓冲的c3时阻塞。结果是wg.Done()将被调用,wg.Wait()也不会阻塞主goroutine。

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup

func main() {
    chan1 := make(chan string)
    chan2 := make(chan string)
    chan3 := make(chan string, 2)
    wg.Add(1)
    go makeChanStr("yeye", chan1, chan3)
    wg.Add(1)
    go makeChanStr("okok", chan2, chan3)
    println(<-chan1)
    println(<-chan2)
    wg.Wait()
    close(chan3)
    for chs := range chan3 {
         println(chs)
    }
}

func makeChanStr(s string, c1 chan string, c2 chan string) {
    defer wg.Done()

    c1 <- "get " + s
    c2 <- "same value"
    fmt.Printf("execute %s\n", s)
}
英文:

This code blocks on wg.Wait() in main goroutine and writing to c1 in workers. To avoid it - read from c1 and c2 prior to wg.Wait() thus unblock workers and they will not block on writing to buffered c3. As a result wg.Done() will be called and wg.Wait() will not block main goroutine as well.

package main

import (
    &quot;fmt&quot;
    &quot;sync&quot;
)

var wg sync.WaitGroup

func main() {
    chan1 := make(chan string)
    chan2 := make(chan string)
    chan3 := make(chan string, 2)
    wg.Add(1)
    go makeChanStr(&quot;yeye&quot;, chan1, chan3)
    wg.Add(1)
    go makeChanStr(&quot;okok&quot;, chan2, chan3)
    println(&lt;-chan1)
    println(&lt;-chan2)
    wg.Wait()
    close(chan3)
    for chs := range chan3 {
         println(chs)
    }
}

func makeChanStr(s string, c1 chan string, c2 chan string) {
    defer wg.Done()

    c1 &lt;- &quot;get &quot; + s
    c2 &lt;- &quot;same value&quot;
    fmt.Printf(&quot;execute %s\n&quot;, s)
}

huangapple
  • 本文由 发表于 2021年6月8日 21:27:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/67887932.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定