尝试同步goroutine时出现死锁错误。

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

Deadlock error when trying to sync goroutines

问题

我面临一个烦人的问题。当我尝试使用wg.Add()来同步我的例程时,会出现死锁错误。

package main

import (
	"fmt"
	"sync"
)

func hello(ch chan int, num int, wg *sync.WaitGroup) {
	for {
		i := <-ch
		if i == num {
			fmt.Println("Hello number:", i)
			ch <- (num - 1)
			defer wg.Done() // Same happens without defer
			return
		}
		ch <- i
	}
}

func main() {
	fmt.Println("Start")

	var wg sync.WaitGroup
	ch := make(chan int)

	for i := 0; i < 10; i++ {
		wg.Add(1)
		go hello(ch, i, &wg)
	}

	ch <- 9

	wg.Wait()

	fmt.Println("End")
}

输出结果:

Start
Hello number: 9
Hello number: 8
Hello number: 7
Hello number: 6
Hello number: 5
Hello number: 4
Hello number: 3
Hello number: 2
Hello number: 1
Hello number: 0
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc04203a20c)
        C:/Go/src/runtime/sema.go:47 +0x3b
sync.(*WaitGroup).Wait(0xc04203a200)
        C:/Go/src/sync/waitgroup.go:131 +0x81
main.main()
        C:/Users/Augusto Dias/Documents/GoLang/MT.go:34 +0x1a0

goroutine 18 [chan send]:
main.hello(0xc0420380c0, 0x0, 0xc04203a200)
        C:/Users/Augusto Dias/Documents/GoLang/MT.go:13 +0x197
created by main.main
        C:/Users/Augusto Dias/Documents/GoLang/MT.go:29 +0x151
exit status 2

当我在for循环之外使用wg.Add(9)时,就没有错误了。

func main() {
	fmt.Println("Start")

	var wg sync.WaitGroup
	ch := make(chan int)

	wg.Add(9) // Use wg.Add(10) will raise deadlock too

	for i := 0; i < 10; i++ {
		go hello(ch, i, &wg)
	}

	ch <- 9

	wg.Wait()
	fmt.Println("End")
}

输出结果:

Start
Hello number: 9
Hello number: 8
Hello number: 7
Hello number: 6
Hello number: 5
Hello number: 4
Hello number: 3
Hello number: 2
Hello number: 1
End

为什么会发生这种情况,我的意思是,为什么例程在我等待它们时会进入睡眠状态?使用相同的通道进行发送和接收可能是问题的根源吗?

英文:

I'm facing an annoying problem. When I try to use wg.Add() to sync my routines, a deadlock error is raised.

package main

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

func hello(ch chan int, num int, wg *sync.WaitGroup) {
	for {
		i := &lt;-ch
		if i == num {
			fmt.Println(&quot;Hello number:&quot;, i)
			ch &lt;- (num - 1)
			defer wg.Done() // Same happens without defer
			return
		}
		ch &lt;- i
	}
}

func main() {
	fmt.Println(&quot;Start&quot;)

	var wg sync.WaitGroup
	ch := make(chan int)

	for i := 0; i &lt; 10; i++ {
		wg.Add(1)
		go hello(ch, i, &amp;wg)
	}

	ch &lt;- 9

	wg.Wait()

	fmt.Println(&quot;End&quot;)
}

Outputs:

Start
Hello number: 9
Hello number: 8
Hello number: 7
Hello number: 6
Hello number: 5
Hello number: 4
Hello number: 3
Hello number: 2
Hello number: 1
Hello number: 0
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc04203a20c)
        C:/Go/src/runtime/sema.go:47 +0x3b
sync.(*WaitGroup).Wait(0xc04203a200)
        C:/Go/src/sync/waitgroup.go:131 +0x81
main.main()
        C:/Users/Augusto Dias/Documents/GoLang/MT.go:34 +0x1a0

goroutine 18 [chan send]:
main.hello(0xc0420380c0, 0x0, 0xc04203a200)
        C:/Users/Augusto Dias/Documents/GoLang/MT.go:13 +0x197
created by main.main
        C:/Users/Augusto Dias/Documents/GoLang/MT.go:29 +0x151
exit status 2

When I use wg.Add(9) outside the for block, I got no error.

func main() {
	fmt.Println(&quot;Start&quot;)

	var wg sync.WaitGroup
	ch := make(chan int)

	wg.Add(9) // Use wg.Add(10) will raise deadlock too

	for i := 0; i &lt; 10; i++ {
		go hello(ch, i, &amp;wg)
	}

	ch &lt;- 9

	wg.Wait()
	fmt.Println(&quot;End&quot;)
}

Outputs:

Start
Hello number: 9
Hello number: 8
Hello number: 7
Hello number: 6
Hello number: 5
Hello number: 4
Hello number: 3
Hello number: 2
Hello number: 1
End

Why is this happening, I mean, why routines goes asleep when I wait for them all? Use the same channel for send and receive can be the source of this problem?

答案1

得分: 3

通道0(调用go hello(ch, 0, &wg))因为它是最后一个活动的通道,所以在这一行上被阻塞。

ch <- (num - 1)

它试图发送到一个通道,但没有人接收。因此,该函数将无限期等待,永远不会完成。

解决此问题的一些建议:

  • 在主循环中创建一个消费者
  • 将通道ch设置为非阻塞的
英文:

Channel 0 (the call go hello(ch, 0, &amp;wg)) since it is the last channel alive gets stuck on this line

ch &lt;- (num - 1)

It is attempting to send to a channel but no one is there to receive it. Thus the function will wait indefinitely and never be done.

Some suggestions for how to remove this problem

  • create a consumer in the main loop
  • make the channel ch non blocking

huangapple
  • 本文由 发表于 2017年3月13日 23:32:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/42767523.html
匿名

发表评论

匿名网友

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

确定