在for循环中产生goroutine时的死锁

时间:2016-08-08 03:44:48

标签: go goroutine

考虑以下go playground

package main

import "fmt"

func main() {

    var chan_array [2]chan int

    chan1 := make(chan int)
    chan2 := make(chan int)

    chan_array[0] = chan1
    chan_array[1] = chan2


    for i := 0; i < 2; i++ {
        go func() {

            select {
                case x := <- chan_array[i]:
                    if (x == 0) {
                        return
                    }       
                    fmt.Println(x)
            }
        }()
    }

    chan1<- 1
    chan2<- 2
    chan1<- 0
    chan2<- 0
}

上面的代码试图创建2个正在运行的goroutine,它们会监听通道以发出信号打印或关闭。

但是上面的代码遇到了死锁。

我不确定为什么

有人可以指出我的错误吗?

由于

2 个答案:

答案 0 :(得分:4)

有一些问题:
i运行时chan_array[i-1]的价值是什么

for i := 0; i < 2; i++ {
    go func() {
        select {
        case x := <- chan_array[i-1]:
            if x == 0 {
                return
            }
            fmt.Println(x)
        }
    }()
}

试试这个:

for i := 0; i < 2; i++ {
    go func(i int) { 
        select {
        case x := <-chan_array[i]:
            if x == 0 {
                return
            }
            fmt.Println(x)
        }
    }(i)
}

让我们简化您的代码(进行一些更正):

package main

import "fmt"

func main() {
    chan1 := make(chan int)
    chan2 := make(chan int)

    go routine(chan1)
    go routine(chan2)

    chan1 <- 1
    chan2 <- 2
    chan1 <- 0
    chan2 <- 0
}

func routine(ch chan int) {
    select {
    case x := <-ch:
        if x == 0 {
            return
        }
        fmt.Println(x)
    }
}

有了这些:

chan1 <- 1
chan2 <- 2

致命错误:

all goroutines are asleep - deadlock!

你的goroutines已经完成了没有goroutines倾听chan1chan1

chan1 <- 0
chan2 <- 0

您更正的工作示例代码是:

package main

import "fmt"

func main() {
    chan1 := make(chan int)
    chan2 := make(chan int)

    go routine(chan1)
    go routine(chan2)

    chan1 <- 1
    chan2 <- 2
    chan1 <- 0
    chan2 <- 0
}

func routine(ch chan int) {
    for {
        select {
        case x := <-ch:
            if x == 0 {
                return
            }
            fmt.Println(x)
        }
    }
}

输出:

1
2

答案 1 :(得分:1)

当goroutines运行时,变量i已经递增。将其作为函数参数传递。

实际上,永远不要依赖goroutines中函数闭包的变量。这太不可靠了。