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

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

why my golang goroutine code get deadlocked

问题

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

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. )
  6. var wg sync.WaitGroup
  7. func main() {
  8. chan1 := make(chan string)
  9. chan2 := make(chan string)
  10. chan3 := make(chan string, 2)
  11. wg.Add(1)
  12. go makeChanStr("yeye", chan1, chan3)
  13. wg.Add(1)
  14. go makeChanStr("okok", chan2, chan3)
  15. wg.Wait()
  16. close(chan3)
  17. println(<-chan1)
  18. println(<-chan2)
  19. for chs := range chan3 {
  20. println(chs)
  21. }
  22. }
  23. func makeChanStr(s string, c1 chan string, c2 chan string) {
  24. defer wg.Done()
  25. c1 <- "get " + s
  26. c2 <- "same value"
  27. fmt.Printf("execute ok %s", s)
  28. }

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

英文:

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

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;sync&quot;
  5. )
  6. var wg sync.WaitGroup
  7. func main() {
  8. chan1 := make(chan string)
  9. chan2 := make(chan string)
  10. chan3 := make(chan string, 2)
  11. wg.Add(1)
  12. go makeChanStr(&quot;yeye&quot;, chan1, chan3)
  13. wg.Add(1)
  14. go makeChanStr(&quot;okok&quot;, chan2, chan3)
  15. wg.Wait()
  16. close(chan3)
  17. println(&lt;-chan1)
  18. println(&lt;-chan2)
  19. for chs := range chan3 {
  20. println(chs)
  21. }
  22. }
  23. func makeChanStr(s string, c1 chan string, c2 chan string) {
  24. defer wg.Done()
  25. c1 &lt;- &quot;get &quot; + s
  26. c2 &lt;- &quot;same value&quot;
  27. fmt.Printf(&quot;execute ok %s&quot;, s)
  28. }

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

  1. go makeChanStr("yeye", chan1, chan3)
  2. go makeChanStr("okok", chan2, chan3)

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

  1. chan1 := make(chan string)

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

  1. chan1 := make(chan string, 1)
  2. 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())

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

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

  1. chan1 := make(chan string)

try change chan1 and chan2 to buffer channels:

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

答案2

得分: 1

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

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. )
  6. var wg sync.WaitGroup
  7. func main() {
  8. chan1 := make(chan string)
  9. chan2 := make(chan string)
  10. chan3 := make(chan string, 2)
  11. wg.Add(1)
  12. go makeChanStr("yeye", chan1, chan3)
  13. wg.Add(1)
  14. go makeChanStr("okok", chan2, chan3)
  15. println(<-chan1)
  16. println(<-chan2)
  17. wg.Wait()
  18. close(chan3)
  19. for chs := range chan3 {
  20. println(chs)
  21. }
  22. }
  23. func makeChanStr(s string, c1 chan string, c2 chan string) {
  24. defer wg.Done()
  25. c1 <- "get " + s
  26. c2 <- "same value"
  27. fmt.Printf("execute %s\n", s)
  28. }
英文:

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.

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;sync&quot;
  5. )
  6. var wg sync.WaitGroup
  7. func main() {
  8. chan1 := make(chan string)
  9. chan2 := make(chan string)
  10. chan3 := make(chan string, 2)
  11. wg.Add(1)
  12. go makeChanStr(&quot;yeye&quot;, chan1, chan3)
  13. wg.Add(1)
  14. go makeChanStr(&quot;okok&quot;, chan2, chan3)
  15. println(&lt;-chan1)
  16. println(&lt;-chan2)
  17. wg.Wait()
  18. close(chan3)
  19. for chs := range chan3 {
  20. println(chs)
  21. }
  22. }
  23. func makeChanStr(s string, c1 chan string, c2 chan string) {
  24. defer wg.Done()
  25. c1 &lt;- &quot;get &quot; + s
  26. c2 &lt;- &quot;same value&quot;
  27. fmt.Printf(&quot;execute %s\n&quot;, s)
  28. }

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:

确定