首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用sync.Cond的Golang偶数奇数打印变量

使用sync.Cond的Golang偶数奇数打印变量
EN

Stack Overflow用户
提问于 2021-12-26 18:23:01
回答 1查看 139关注 0票数 -3

我在戈朗学到了更多关于并发的知识。我试图用两个不同的线程打印偶数。我知道打印更多关于共享资源的同步/顺序访问,而不是并发,仍然值得一试。

我知道它可以使用通道或使用等待组,我已经这样做了,但仍然试图用sync.cond实现同样的目标。

在下面的代码中,如果在两个函数中都启用了最后一个fmt.Println,那么它会打印10个以上的数字,但是如果我注释它并启用first fmt.Print Functional,那么它可以正常工作。非常奇怪的输出。我无法理解为什么会发生这种情况,有人能让我知道我做错了什么吗?

提前谢谢。

代码语言:javascript
运行
复制
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

围棋操场的链接:

04JiPI

EN

回答 1

Stack Overflow用户

发布于 2021-12-26 20:46:13

最突出的问题是循环:

代码语言:javascript
运行
复制
for val < 10 {
    go odd(&val, cond)
    go even(&val, cond)
}

我猜您的目的是启动两个员工并等待终止事件(val到达10)。

撇开数据竞赛不谈,上面是一个很紧的循环,在等待终止事件时,它会不断地生成多个(和不必要的)“奇数”和“偶数”goroutines,从而产生不可预测的结果。

通过将这一行添加到循环中,您可以看到戈鲁蒂河爆炸

代码语言:javascript
运行
复制
fmt.Println("goroutine #", runtime.NumGoroutine())

要解决这个问题,您需要为odd()even()启动一个单独的goroutine,并使用一个“已完成”通道或上下文取消来向所有goroutines发出信号。这就否定了投票val --这是一种数据--的必要性,因为您正在阅读它,而在其他goroutine中更新它,而没有在“读取”结束时进行任何协调。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70488858

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档