我在戈朗学到了更多关于并发的知识。我试图用两个不同的线程打印偶数。我知道打印更多关于共享资源的同步/顺序访问,而不是并发,仍然值得一试。
我知道它可以使用通道或使用等待组,我已经这样做了,但仍然试图用sync.cond实现同样的目标。
在下面的代码中,如果在两个函数中都启用了最后一个fmt.Println,那么它会打印10个以上的数字,但是如果我注释它并启用first fmt.Print Functional,那么它可以正常工作。非常奇怪的输出。我无法理解为什么会发生这种情况,有人能让我知道我做错了什么吗?
提前谢谢。
package main
import (
"fmt"
"sync"
"time"
)
var done bool
func odd(name *int, c *sync.Cond) {
//fmt.Println(*name, "ODD ")
if *name >= 9 {
return
}
c.L.Lock()
for !done {
c.Wait()
}
*name++
done = false
fmt.Println(*name, "ODD")
c.L.Unlock()
c.Signal()
}
func even(name *int, c *sync.Cond) {
//fmt.Println(*name, "EVEN ")
if *name >= 9 {
return
}
c.L.Lock()
for done == true {
c.Wait()
}
done = true
*name++
fmt.Println(*name, "EVEN ")
c.L.Unlock()
c.Signal()
}
func main() {
done = false
cond := sync.NewCond(&sync.Mutex{})
val := 0
for val < 10 {
go odd(&val, cond)
go even(&val, cond)
}
time.Sleep(10 * time.Second)
fmt.Println("val final:= ", val)
}当最后打印启用时,第一次输出
一平
2个奇数
3平
4奇数
5平
6奇数
七平
8奇数
九平
十奇数
11平
12奇数
13平
14奇数
十五平
16奇数
十七平
18奇数
19平
二十多
21平
22奇数
23平
24奇数
25平
26奇数
二七平
28奇数
二十九平
三十多
31平
32奇数
三十三平
34奇数
三十五平
36奇数
37平
38奇数
39平
四十多
41平
42奇数
43平
44奇数
45平
46奇数
47平
48奇数
49平
五十多
val final:= 51
第一次打印启用时的输出
零偶数
1奇数
2个奇数
4奇数
4平
2个奇数
2偶
6平
十奇数
2个奇数
2偶
2个奇数
2偶
十奇数
2偶
2个奇数
2偶
2偶
2偶
2个奇数
2偶
2个奇数
2偶
2个奇数
2偶
2个奇数
2偶
2个奇数
2偶
2个奇数
2偶
2个奇数
2偶
2个奇数
2偶
2个奇数
2偶
2个奇数
2偶
2个奇数
2个奇数
2个奇数
2偶
4奇数
4平
4奇数
4平
4奇数
4平
4奇数
4平
6平
6奇数
6平
6奇数
6平
八平
8奇数
八平
十平
八平
十平
十奇数
十平
2个奇数
十平
十奇数
2偶
十平
十平
val final:= 10
围棋操场的链接:
发布于 2021-12-26 20:46:13
最突出的问题是循环:
for val < 10 {
go odd(&val, cond)
go even(&val, cond)
}我猜您的目的是启动两个员工并等待终止事件(val到达10)。
撇开数据竞赛不谈,上面是一个很紧的循环,在等待终止事件时,它会不断地生成多个(和不必要的)“奇数”和“偶数”goroutines,从而产生不可预测的结果。
通过将这一行添加到循环中,您可以看到戈鲁蒂河爆炸:
fmt.Println("goroutine #", runtime.NumGoroutine())要解决这个问题,您需要为odd()和even()启动一个单独的goroutine,并使用一个“已完成”通道或上下文取消来向所有goroutines发出信号。这就否定了投票val --这是一种数据--的必要性,因为您正在阅读它,而在其他goroutine中更新它,而没有在“读取”结束时进行任何协调。
https://stackoverflow.com/questions/70488858
复制相似问题