GOLANG:学习goroutine让我陷入了死锁。

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

GOLANG: Learning goroutine took me to a deadlock

问题

我是一个GO的新手,我正在努力弄清楚goroutines是如何工作以及如何同步它们。
这是我写的一个简单程序,用来学习它们的一些知识:

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. "time"
  6. )
  7. func printAfterDelay(delay time.Duration, message string, wg *sync.WaitGroup) {
  8. time.Sleep(delay)
  9. fmt.Println(message)
  10. wg.Done()
  11. }
  12. func add(a int, b int, chan1 chan int, wg *sync.WaitGroup) {
  13. c := a + b
  14. chan1 <- c
  15. //close(chan1)
  16. wg.Done()
  17. }
  18. func printer(chan1 chan int, wg *sync.WaitGroup) {
  19. for result := range chan1 {
  20. //result := <-chan1
  21. //time.Sleep(2000 * time.Millisecond)
  22. fmt.Println(result)
  23. }
  24. close(chan1)
  25. wg.Done()
  26. }
  27. func main() {
  28. //var wg sync.WaitGroup
  29. wg := &sync.WaitGroup{}
  30. fmt.Println("Start...")
  31. wg.Add(1)
  32. go printAfterDelay(2000*time.Millisecond, "Try", wg)
  33. chan1 := make(chan int)
  34. wg.Add(1)
  35. go add(5, 4, chan1, wg)
  36. wg.Add(1)
  37. go add(3, 1, chan1, wg)
  38. wg.Add(1)
  39. go printer(chan1, wg)
  40. //time.Sleep(3000 * time.Millisecond)
  41. wg.Wait()
  42. fmt.Println("End")
  43. }

add函数接受两个整数,将它们相加并将结果传递给一个通道(chan)。
printer函数从通道中获取结果并打印它们。
这两个函数在main()中作为goroutines调用,所以我还传递了一个WaitGroup作为指针,在调用goroutines之前增加它,在函数结束时减少它。

无论如何,当我执行编译后的程序时,它打印出:

  1. Start...
  2. 9
  3. 4
  4. Try
  5. fatal error: all goroutines are asleep - deadlock!
  6. goroutine 16 [semacquire]:
  7. sync.runtime_Semacquire(0x18334008)
  8. /usr/lib/go/src/pkg/runtime/sema.goc:199 +0x37
  9. sync.(*WaitGroup).Wait(0x183240e0)
  10. /usr/lib/go/src/pkg/sync/waitgroup.go:129 +0x12d
  11. main.main()
  12. /home/ettore/go/src/example/goroutine/main.go:52 +0x1e5
  13. goroutine 19 [finalizer wait]:
  14. runtime.park(0x80599e0, 0x814f000, 0x814e3e9)
  15. /usr/lib/go/src/pkg/runtime/proc.c:1369 +0x94
  16. runtime.parkunlock(0x814f000, 0x814e3e9)
  17. /usr/lib/go/src/pkg/runtime/proc.c:1385 +0x3
  18. frunfinq()
  19. /usr/lib/go/src/pkg/runtime/mgc0.c:2644 +0xc5
  20. runtime.goexit()
  21. /usr/lib/go/src/pkg/runtime/proc.c:1445
  22. goroutine 23 [chan receive]:
  23. main.printer(0x1831a090, 0x183240e0)
  24. /home/ettore/go/src/example/goroutine/main.go:23 +0x46
  25. created by main.main
  26. /home/ettore/go/src/example/goroutine/main.go:49 +0x1d7

问题出在哪里?有什么问题吗?

谢谢!

英文:

I'm a GO newbie and I'm trying to figure out how does goroutines work and how to synchronize them.
This is a simple program I wrote to learn something about them:

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;sync&quot;
  5. &quot;time&quot;
  6. )
  7. func printAfterDelay(delay time.Duration, message string, wg *sync.WaitGroup) {
  8. time.Sleep(delay)
  9. fmt.Println(message)
  10. wg.Done()
  11. }
  12. func add(a int, b int, chan1 chan int, wg *sync.WaitGroup) {
  13. c := a + b
  14. chan1 &lt;- c
  15. //close(chan1)
  16. wg.Done()
  17. }
  18. func printer(chan1 chan int, wg *sync.WaitGroup) {
  19. for result := range chan1 {
  20. //result := &lt;-chan1
  21. //time.Sleep(2000 * time.Millisecond)
  22. fmt.Println(result)
  23. }
  24. close(chan1)
  25. wg.Done()
  26. }
  27. func main() {
  28. //var wg sync.WaitGroup
  29. wg := &amp;sync.WaitGroup{}
  30. fmt.Println(&quot;Start...&quot;)
  31. wg.Add(1)
  32. go printAfterDelay(2000*time.Millisecond, &quot;Try&quot;, wg)
  33. chan1 := make(chan int)
  34. wg.Add(1)
  35. go add(5, 4, chan1, wg)
  36. wg.Add(1)
  37. go add(3, 1, chan1, wg)
  38. wg.Add(1)
  39. go printer(chan1, wg)
  40. //time.Sleep(3000 * time.Millisecond)
  41. wg.Wait()
  42. fmt.Println(&quot;End&quot;)
  43. }

The add function takes two int, sums them and pass the result to a chan.
The printer function takes the results from the chan and print them.
The two funtions are called in main() as goroutines, so i also passed a WaitGroup as a pointer, that is incremented before calling the goroutines and decremented when the functions end.

Anyway when I execute the compiled program it prints:

  1. Start...
  2. 9
  3. 4
  4. Try
  5. fatal error: all goroutines are asleep - deadlock!
  6. goroutine 16 [semacquire]:
  7. sync.runtime_Semacquire(0x18334008)
  8. /usr/lib/go/src/pkg/runtime/sema.goc:199 +0x37
  9. sync.(*WaitGroup).Wait(0x183240e0)
  10. /usr/lib/go/src/pkg/sync/waitgroup.go:129 +0x12d
  11. main.main()
  12. /home/ettore/go/src/example/goroutine/main.go:52 +0x1e5
  13. goroutine 19 [finalizer wait]:
  14. runtime.park(0x80599e0, 0x814f000, 0x814e3e9)
  15. /usr/lib/go/src/pkg/runtime/proc.c:1369 +0x94
  16. runtime.parkunlock(0x814f000, 0x814e3e9)
  17. /usr/lib/go/src/pkg/runtime/proc.c:1385 +0x3
  18. frunfinq()
  19. /usr/lib/go/src/pkg/runtime/mgc0.c:2644 +0xc5
  20. runtime.goexit()
  21. /usr/lib/go/src/pkg/runtime/proc.c:1445
  22. goroutine 23 [chan receive]:
  23. main.printer(0x1831a090, 0x183240e0)
  24. /home/ettore/go/src/example/goroutine/main.go:23 +0x46
  25. created by main.main
  26. /home/ettore/go/src/example/goroutine/main.go:49 +0x1d7

Where and what is the problem(s)?

Thanks!

答案1

得分: 1

以下是翻译好的内容:

以下代码是有效的。我的意思是它不会发生死锁。
由于将打印函数放在通道的范围循环中,它会在通道关闭后自动停止。我在最后附近添加了3秒的延迟,以便try循环有足够的时间打印。不过,建议阅读文档,它会解释这些细节的100%。

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. "time"
  6. )
  7. func printAfterDelay(delay time.Duration, message string, wg *sync.WaitGroup) {
  8. time.Sleep(delay)
  9. fmt.Println(message)
  10. }
  11. func add(a int, b int, chan1 chan int, wg *sync.WaitGroup) {
  12. c := a + b
  13. chan1 <- c
  14. wg.Done()
  15. }
  16. func printer(chan1 chan int, wg *sync.WaitGroup) {
  17. for result := range chan1 {
  18. fmt.Println(result)
  19. }
  20. }
  21. func main() {
  22. //var wg sync.WaitGroup
  23. wg := &sync.WaitGroup{}
  24. fmt.Println("Start...")
  25. go printAfterDelay(2000*time.Millisecond, "Try", wg)
  26. chan1 := make(chan int)
  27. wg.Add(1)
  28. go add(5, 4, chan1, wg)
  29. wg.Add(1)
  30. go add(3, 1, chan1, wg)
  31. go printer(chan1, wg)
  32. time.Sleep(3000 * time.Millisecond)
  33. wg.Wait()
  34. close(chan1)
  35. fmt.Println("End")
  36. }
英文:

The following works. By that I mean that it doesn't deadlock.
Since you have the printer function in a range loop over the channel, it'll automatically stop after the channel is closed. I added the 3 sec delay near the end to give the try loop time to print. Read the documentation though. It'll explain 100% of these details.

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;sync&quot;
  5. &quot;time&quot;
  6. )
  7. func printAfterDelay(delay time.Duration, message string, wg *sync.WaitGroup) {
  8. time.Sleep(delay)
  9. fmt.Println(message)
  10. }
  11. func add(a int, b int, chan1 chan int, wg *sync.WaitGroup) {
  12. c := a + b
  13. chan1 &lt;- c
  14. wg.Done()
  15. }
  16. func printer(chan1 chan int, wg *sync.WaitGroup) {
  17. for result := range chan1 {
  18. fmt.Println(result)
  19. }
  20. }
  21. func main() {
  22. //var wg sync.WaitGroup
  23. wg := &amp;sync.WaitGroup{}
  24. fmt.Println(&quot;Start...&quot;)
  25. go printAfterDelay(2000*time.Millisecond, &quot;Try&quot;, wg)
  26. chan1 := make(chan int)
  27. wg.Add(1)
  28. go add(5, 4, chan1, wg)
  29. wg.Add(1)
  30. go add(3, 1, chan1, wg)
  31. go printer(chan1, wg)
  32. time.Sleep(3000 * time.Millisecond)
  33. wg.Wait()
  34. close(chan1)
  35. fmt.Println(&quot;End&quot;)
  36. }

huangapple
  • 本文由 发表于 2015年4月7日 04:56:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/29479562.html
匿名

发表评论

匿名网友

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

确定