英文:
waitgroup.Wait() causing dead lock
问题
我正在尝试弄清楚为什么在使用waitgroup.Wait()时会出现死锁的情况。
当我像这样运行代码时,它会打印出fatal error: all goroutines are asleep - deadlock!。
我尝试将ch更改为带缓冲的通道,问题得到解决。但我真的想知道为什么会出现死锁。
英文:
I'm trying to figure out why I have a dead lock with waitgroup.Wait()
package main
import (
	"fmt"
	"sync"
)
var wg sync.WaitGroup
func foo(c chan int, i int) {
	defer wg.Done()
	c <- i
}
func main() {
	ch := make(chan int)
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go foo(ch, i)
	}
	wg.Wait()
	close(ch)
	for item := range ch {
		fmt.Println(item)
	}
}
When I run it like this, it prints fatal error: all goroutines are asleep - deadlock!
I tried to change ch to a buffered channel and that solved the problem. But I really want to know why is there a dead lock.
答案1
得分: 2
我已经注释掉了你程序逻辑不正确的部分:
package main
import (
	"fmt"
	"sync"
)
var wg sync.WaitGroup
func foo(c chan int, i int) {
	defer wg.Done()
	c <- i
}
func main() {
	ch := make(chan int) // 无缓冲通道
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go foo(ch, i)
	}
	// wg.Wait 等待所有 goroutine 完成,但只有在通道发送成功的情况下才可能完成。
	// 在这种情况下,由于你的接收者 "for item := range ch" 在下面,所以不可能完成,导致死锁。
	wg.Wait()
	// 理想情况下,关闭通道应该是发送者的责任。
	// 并且在接收者之前关闭一个无缓冲通道是不正确的。
	close(ch)
	for item := range ch {
		fmt.Println(item)
	}
}
修正后的程序:
package main
import (
	"fmt"
	"sync"
)
var wg sync.WaitGroup
func foo(c chan int, i int) {
	defer wg.Done()
	c <- i
}
func main() {
	ch := make(chan int)
	go func() {
		for item := range ch {
			fmt.Println(item)
		}
	}()
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go foo(ch, i)
	}
	wg.Wait()
	close(ch)
}
英文:
I've commented out the parts where your program's logic is not correct:
package main
import (
	"fmt"
	"sync"
)
var wg sync.WaitGroup
func foo(c chan int, i int) {
	defer wg.Done()
	c <- i
}
func main() {
	ch := make(chan int) // unbuffered channel
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go foo(ch, i)
	}
	// wg.Wait is waiting for all goroutines to finish but that's
	// only possible if the send to channel succeeds. In this case,
	// it is not possible as your receiver "for item := range ch" is below
	// this. Hence, a deadlock.
	wg.Wait()
	// Ideally, it should be the sender's duty to close the channel.
	// And closing a channel before the receiver where the channel
	// is unbuffered is not correct.
	close(ch)
	for item := range ch {
		fmt.Println(item)
	}
}
Corrected program:
package main
import (
	"fmt"
	"sync"
)
var wg sync.WaitGroup
func foo(c chan int, i int) {
	defer wg.Done()
	c <- i
}
func main() {
	ch := make(chan int)
	go func() {
		for item := range ch {
			fmt.Println(item)
		}
	}()
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go foo(ch, i)
	}
	wg.Wait()
	close(ch)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论