想起之前一道题,两个线程,轮流对同一个数进行加一操作,每个线程执行10次。
java中使用wait/notify操作,go我想到的是使用两个无缓存channel实现同样的功能
package main
import (
"fmt"
"sync"
)
func increment(ch1, ch2 chan struct{}, x *int, id int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 10; i++ {
<-ch1
*x++
fmt.Println("id :", id, ", x :", *x)
ch2 <- struct{}{}
}
fmt.Println(id, " end")
}
func main() {
ch1 := make(chan struct{})
ch2 := make(chan struct{})
x := 0
var wg sync.WaitGroup
wg.Add(2)
go increment(ch1, ch2, &x, 1, &wg)
go increment(ch2, ch1, &x, 2, &wg)
ch1 <- struct{}{}
wg.Wait()
close(ch1)
close(ch2)
}
执行发现功能可以实现,但是最后都会报一个 fatal error: all goroutines are asleep - deadlock! 然后退出。经过网上查询知道:
Go 语言的通道(channel)在以下情况下会被判断为死锁:
我们分析上面的代码知道当第二个线程执行完最后一次有一个对ch1的写入操作,这个操作导致了死锁,所以我们要在最后一次的时候停止对ch1的写入操作
package main
import (
"fmt"
"sync"
)
func increment(ch1, ch2 chan struct{}, x *int, id int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 10; i++ {
<-ch1
*x++
fmt.Println("id :", id, ", x :", *x)
if *x != 20{
ch2 <- struct{}{}
}
}
}
func main() {
ch1 := make(chan struct{})
ch2 := make(chan struct{})
x := 0
var wg sync.WaitGroup
wg.Add(2)
go increment(ch1, ch2, &x, 1, &wg)
go increment(ch2, ch1, &x, 2, &wg)
ch1 <- struct{}{}
wg.Wait()
close(ch1)
close(ch2)
}