英文:
Go:How to print dog, cat and fish alternately for 3 times through 3 goroutine without deadlock?
问题
- 如何使用sync.WaitGroup解决死锁问题?
我的代码可以正确打印结果,但会导致死锁。
我目前能想到的解决方法是:用time.Sleep替换sync.WaitGroup。
但我想知道如何使用sync.WaitGroup解决死锁问题?
- 这是运行的结果:
dog: 0
cat: 0
fish: 0
dog: 1
cat: 1
fish: 1
dog: 2
cat: 2
fish: 2
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xeaeeb0)
D:/GoSDK/go1.17.3/src/runtime/sema.go:56 +0x25
sync.(*WaitGroup).Wait(0x60)
D:/GoSDK/go1.17.3/src/sync/waitgroup.go:130 +0x71
- 这是我的代码:
func main(){
wg := sync.WaitGroup{}
wg.Add(3)
const Count = 3
ch1, ch2, ch3 := make(chan bool), make(chan bool), make(chan bool)
go func() {
defer wg.Done()
for i := 0; i < Count; i++ {
<-ch1
fmt.Println("dog:", i)
//notice 2
ch2 <- true
}
}()
go func() {
defer wg.Done()
for i := 0; i < Count; i++ {
//wait 1
<-ch2
fmt.Println("cat:", i)
//notice 3
ch3 <- true
}
}()
go func() {
defer wg.Done()
for i := 0; i < Count; i++ {
//wait 2
<-ch3
fmt.Println("fish:", i)
//notice 1
ch1 <- true
}
}()
//notic 1
ch1 <- true
wg.Wait()
}
英文:
1.How to use sync.WaitGroup to solve deadlock?
My code can print the result correctly, but it will cause deadlock.
What I can think of now is:replace sync.WaitGroup with time.Sleep.
But I want to know how to use sync.WaitGroup to solve deadlock?
- This is the result of the run:
dog: 0
cat: 0
fish: 0
dog: 1
cat: 1
fish: 1
dog: 2
cat: 2
fish: 2
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xeaeeb0)
D:/GoSDK/go1.17.3/src/runtime/sema.go:56 +0x25
sync.(*WaitGroup).Wait(0x60)
D:/GoSDK/go1.17.3/src/sync/waitgroup.go:130 +0x71
- This is my code:
func main(){
wg := sync.WaitGroup{}
wg.Add(3)
const Count = 3
ch1, ch2, ch3 := make(chan bool), make(chan bool), make(chan bool)
go func() {
defer wg.Done()
for i := 0; i < Count; i++ {
<-ch1
fmt.Println("dog:", i)
//notice 2
ch2 <- true
}
}()
go func() {
defer wg.Done()
for i := 0; i < Count; i++ {
//wait 1
<-ch2
fmt.Println("cat:", i)
//notice 3
ch3 <- true
}
}()
go func() {
defer wg.Done()
for i := 0; i < Count; i++ {
//wait 2
<-ch3
fmt.Println("fish:", i)
//notice 1
ch1 <- true
}
}()
//notic 1
ch1 <- true
wg.Wait()
}
答案1
得分: 0
问题在于没有任何goroutine在等待ch1
。所以在第三个goroutine的最后一次迭代中,锁定了(ch1 <- true
)。
所以你需要一种方法来识别链条停止的情况。
我快速而谦虚的建议:
func main() {
wg := sync.WaitGroup{}
wg.Add(3)
const Count = 3
ch1, ch2, ch3 := make(chan bool), make(chan bool), make(chan bool)
chainEnded := make(chan struct{})
go func() {
defer wg.Done()
for i := 0; i < Count; i++ {
<-ch1
fmt.Println("dog:", i)
//notice 2
ch2 <- true
}
chainEnded <- struct{}{}
}()
go func() {
defer wg.Done()
for i := 0; i < Count; i++ {
//wait 1
<-ch2
fmt.Println("cat:", i)
//notice 3
ch3 <- true
}
}()
go func() {
defer wg.Done()
for i := 0; i < Count; i++ {
//wait 2
<-ch3
fmt.Println("fish:", i)
//notice 1
ch1 <- true
}
}()
//notic 1
ch1 <- true
<-chainEnded // wait for the loop to end and send to this chan
<-ch1 // unblock the attempt to chain of the last routine
wg.Wait()
}
英文:
The issue here is that no go routine is waiting for ch1
. So on the last iteration of the third goroutine locks (ch1 <- true
).
So what you need is a way to recognize that the chain stopped.
My fast and humble suggestion:
func main() {
wg := sync.WaitGroup{}
wg.Add(3)
const Count = 3
ch1, ch2, ch3 := make(chan bool), make(chan bool), make(chan bool)
chainEnded := make(chan struct{})
go func() {
defer wg.Done()
for i := 0; i < Count; i++ {
<-ch1
fmt.Println("dog:", i)
//notice 2
ch2 <- true
}
chainEnded <- struct{}{}
}()
go func() {
defer wg.Done()
for i := 0; i < Count; i++ {
//wait 1
<-ch2
fmt.Println("cat:", i)
//notice 3
ch3 <- true
}
}()
go func() {
defer wg.Done()
for i := 0; i < Count; i++ {
//wait 2
<-ch3
fmt.Println("fish:", i)
//notice 1
ch1 <- true
}
}()
//notic 1
ch1 <- true
<-chainEnded // wait for the loop to end and send to this chan
<-ch1 // unblock the attempt to chain of the last routine
wg.Wait()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论