【问题标题】:throw all goroutines are asleep - deadlock! ------- Error in Google's GO抛出所有 goroutines 都睡着了 - 死锁! -------- Google GO 中的错误
【发布时间】:2012-01-06 13:11:24
【问题描述】:

我想编写三个并发的 go 例程,它们相互发送整数。现在,我的代码已正确编译,但是在第一次执行后它给出了错误“抛出:所有 goroutines 都处于睡眠状态 - 死锁!”。我试图找到错误,但我无法在代码逻辑中找到任何错误。任何人都可以帮助我找到我的代码中的错误。我的代码如下。

package main

import "rand"

func Routine1(command12 chan int, response12 chan int, command13 chan int, response13 chan int) {

    // z12 is a variable which stores the value comming from channel 2 and z13 is a variable which stores the value comming from channel 3.

    z12 := 200
    z13 := 200
    m12 := false
    m13 := false
    y := 0

    for i := 0; i < 20; i++ {
        y = rand.Intn(100)

        // If y's value is not 0 then the value will be sent to routine 2 or 3 according to   prime or not.
        // If y's value is 0 then process state (the varibles used by it means z12, z13) and channel state will be saved.[routine 1 is initiator]

        if y == 0 {
            print(z12, "    z12 STATE SAVED\n")
            print(z13, "    z13 STATE SAVED\n")

            // Routine 1 is initiator,  it sends 0 to make other process to save the state.

            y = 0
            command12 <- y
            command13 <- y

            // Untill routine 2 and 3 does not send 0, process 1 is on channel saving state (it's process state is already saved).
            // When routine 1 recives 0 from both other processes, channel is saved and routine 1 retuns to it's common routine procedure.
            // When routine 1 recives 0 from any other processes, saving channel bettwen them is stopped.
            // m12, m13 is used to mark whether 0 recived or not.

            for m12 != true || m13 != true {
                select {
                case cmd1 := <-response12:
                    {
                        z12 = cmd1
                        if z12 != 0 {
                            print(z12, "    z12  Channel Saving.... \n")
                            y = rand.Intn(100)
                            command12 <- y
                        }
                        if z12 == 0 {
                            m12 = true
                            print(" z12  Channel Saving Stopped \n")
                        }
                    }

                case cmd2 := <-response13:
                    {
                        z13 = cmd2
                        if z13 != 0 {
                            print(z13, "    z13  Channel Saving.... \n")
                            y = rand.Intn(100)
                            command13 <- y
                        }
                        if z13 == 0 {
                            m13 = true
                            print("    z13  Channel Saving Stopped \n")
                        }
                    }
                }

            }

            // After saving process state it retuns to it's normal behaviour.

            m12 = false
            m13 = false
        }

        if y != 0 {

            // If y value is not 0, routine 1 just sends int to other process according to prime or not and recives int accordingly.

            if y%2 == 0 {
                command12 <- y
            }

            if y%2 != 0 {
                command13 <- y
            }
            select {
            case cmd1 := <-response12:
                {
                    z12 = cmd1
                    print(z12, "    z12\n")
                }
            case cmd2 := <-response13:
                {
                    z13 = cmd2
                    print(z13, "   z13\n")
                }
            }
        }
    }
    close(command12)
    close(command13)
}


//Routine 2 (or 3) is not an initiator (means it can't send 0). When it recives 0 (from routine 1 or 3) it save the state of process and the state of the channel from which it recived).
// When it recives 0 from both other two routine, it saves all channel state and returns to it's common behaviour. [same in routine 3]

func Routine2(command12 chan int, response12 chan int, command23 chan int, response23 chan int) {
    z21 := 200
    z23 := 200
    m21 := false
    m23 := false

    for i := 0; i < 20; i++ {
        select {
        case x, open := <-command12:
            {
                if !open {
                    return
                }
                if x != 0 && m23 != true {
                    z21 = x
                    print(z21, "   z21\n")
                }
                if x != 0 && m23 == true {
                    z21 = x
                    print(z21, "   z21 Channel Saving \n")
                }
                if x == 0 {
                    m21 = true
                    if m21 == true && m23 == true {
                        print(" z21 and z23 Channel Saving Stopped \n")
                        m23 = false
                        m21 = false
                    }
                    if m21 == true && m23 != true {
                        z21 = x
                        print(z21, "   z21  Channel Saved \n")

                    }

                }
            }

        case x, open := <-response23:
            {
                if !open {
                    return
                }
                if x != 0 && m21 != true {
                    z23 = x
                    print(z23, "   z21\n")
                }
                if x != 0 && m21 == true {
                    z23 = x
                    print(z23, "   z23 Channel Saving \n")
                }
                if x == 0 {
                    m23 = true
                    if m21 == true && m23 == true {
                        print(" z23 Channel Saving Stopped \n")
                        m23 = false
                        m21 = false
                    }
                    if m23 == true && m21 != true {
                        z23 = x
                        print(z23, "   z23  Channel Saved \n")
                    }

                }
            }
        }

        if m23 == false && m21 == false {
            y := rand.Intn(100)
            if y%2 == 0 {
                if y == 0 {
                    y = 10
                    response12 <- y
                }
            }

            if y%2 != 0 {
                if y == 0 {
                    y = 10
                    response23 <- y
                }
            }
        }

        if m23 == true && m21 != true {
            y := rand.Intn(100)
            response12 <- y
        }

        if m23 != true && m21 == true {
            y := rand.Intn(100)
            command23 <- y
        }

    }
    close(response12)
    close(command23)
}

func Routine3(command13 chan int, response13 chan int, command23 chan int, response23 chan int) {
    z31 := 200
    z32 := 200
    m31 := false
    m32 := false

    for i := 0; i < 20; i++ {
        select {
        case x, open := <-command13:
            {
                if !open {
                    return
                }
                if x != 0 && m32 != true {
                    z31 = x
                    print(z31, "   z21\n")
                }
                if x != 0 && m32 == true {
                    z31 = x
                    print(z31, "   z31 Channel Saving \n")
                }
                if x == 0 {
                    m31 = true
                    if m31 == true && m32 == true {
                        print(" z21 Channel Saving Stopped \n")
                        m31 = false
                        m32 = false
                    }
                    if m31 == true && m32 != true {
                        z31 = x
                        print(z31, "   z31  Channel Saved \n")

                    }

                }
            }

        case x, open := <-command23:
            {
                if !open {
                    return
                }
                if x != 0 && m31 != true {
                    z32 = x
                    print(z32, "   z32\n")
                }
                if x != 0 && m31 == true {
                    z32 = x
                    print(z32, "   z32 Channel Saving \n")
                }
                if x == 0 {
                    m32 = true
                    if m31 == true && m32 == true {
                        print(" z32 Channel Saving Stopped \n")
                        m31 = false
                        m32 = false
                    }
                    if m32 == true && m31 != true {
                        z32 = x
                        print(z32, "   z32  Channel Saved \n")

                    }

                }
            }
        }
        if m31 == false && m32 == false {
            y := rand.Intn(100)
            if y%2 == 0 {
                response13 <- y
            }

            if y%2 != 0 {
                response23 <- y
            }
        }

        if m31 == true && m32 != true {
            y := rand.Intn(100)
            response13 <- y
        }

        if m31 != true && m32 == true {
            y := rand.Intn(100)
            response23 <- y
        }

    }
    close(response13)
    close(response23)
}


func main() {

    // Three concurrent channels are created to pass integers to each other.
    // command 12 used to send int and response12 is used to receive int from routine 1 to routine 2.
    // response 12 used to send int and command 12 is used to receive int from routine 2 to routine 1. {so as for others}

    command12 := make(chan int)
    response12 := make(chan int)
    command13 := make(chan int)
    response13 := make(chan int)
    command23 := make(chan int)
    response23 := make(chan int)

    go Routine1(command12, response12, command13, response13)
    go Routine2(command12, response12, command23, response23)
    Routine3(command13, response13, command23, response23)
}

【问题讨论】:

  • 您可能应该删除所有不属于您的问题的内容。如果您仍有问题,请发布该代码,最好是格式正确的。
  • 我没有删除所有这些评论,因为根据我的观点,这将使我的意图变得清晰。 Nd关于格式,请说明我应该如何使它更好。谢谢。
  • 我确定达斯汀说的不是 cmets。尝试用更少的代码重现问题。更好的变量和函数名称也会有所帮助。
  • 谢谢埃文,我明白了。我希望,一段时间后我可以更好地理解它。

标签: go concurrent-programming goroutine


【解决方案1】:

正如其他人所说 - 你的代码太复杂了,我无法快速找出它的预期逻辑。无论如何,“技术分析”方法带来了一些小东西。当将 Gosched 作为默认情况添加到选择语句 使通道缓冲时 - 然后代码不再出现死锁。虽然我不知道它在做什么,也不知道它是否做了你想要它做的事情。

在我看来,从查看代码来看,行为是不确定的(?)。无论如何,我认为原始代码可能被设计破坏了(例如,一些循环看起来像是在忙着等待,即使它们运行了 N 次硬编码,原文如此!),很抱歉。

“工作”(== 谁知道它在做什么)代码:http://play.golang.org/p/dcUpeJ9EUa

PS:缓冲区大小 const @ line 325 不能低于 4(通过每周试运行),并且似乎提供了另一种更改代码行为的方法。

【讨论】:

    【解决方案2】:

    我不知道你的问题的答案,但是Routine3 中的switch 语句看起来有问题,因为它包含两个相同的case 语句(这让我想知道为什么6g 不会抱怨这个代码)。

    一些使您的代码更清晰的建议:

    • 正如 Evan 已经指出的那样,请尝试为您的变量提供更具描述性的名称。 if someConditionIsMet 的代码比 if m23 == false 更容易理解。
    • 通过将常用部分分解为函数来干燥代码。
    • 删除无效代码,例如将布尔值设置为真,然后检查它是否为真或检查奇数是否等于零。
    • 考虑使用else 而不是if &lt;condition&gt; {...}; if &lt;negated condition&gt; {...}

    我建议尝试提出单元测试,详尽地描述您的函数的预期行为。这不仅可以帮助您找到错误,还可以提高您的编码技能。根据我的经验,考虑到测试的代码通常比未经测试的代码更容易理解、维护和发展。

    黑客愉快:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-16
      • 2016-04-06
      • 2023-02-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-30
      相关资源
      最近更新 更多