与频道和goroutines同步

时间:2013-05-26 20:23:37

标签: go deadlock channel

我正在尝试实施一个“工人”系统,但我遇到了一些问题,以确定其自身死锁的原因

通过调用fillQueue()

执行代码

我不明白为什么我的代码最终出现在一个dealock中(正在进程正在等待“process()”的第二行,从通道“queue”读取,而另一个正在等待“fillQueue”结束时()“等待服务员阅读。

我不明白为什么它从未得到服务员的阅读。

func process(queue chan *entry, waiters chan bool) {
        for {
                entry, ok := <-queue
                if ok == false {
                        break
                }
                fmt.Println("worker: " + entry.name)
                entry.name = "whatever"
        }
        fmt.Println("worker finished")
        waiters <- true
}

func fillQueue(q *myQueue) {
        // fill our queue                                                                                                                                                                       
        queue := make(chan *entry, len(q.pool))
        for _, entry := range q.pool {
                fmt.Println("push entry")
                queue <- entry
        }
        fmt.Printf("entry cap: %d\n", cap(queue))
        // start the readers                                                                                                                                                                    
        var total_threads int
        if q.maxConcurrent <= len(q.pool) {
                total_threads = q.maxConcurrent
        } else {
                total_threads = len(q.pool)
        }
        waiters := make(chan bool, total_threads)
        fmt.Printf("waiters cap: %d\n", cap(waiters))
        var threads int
        for threads = 0; threads < total_threads; threads++ {
                fmt.Println("start worker")
                go process(queue, waiters)
        }
        fmt.Printf("threads started: %d\n", threads)
        for ; threads > 0; threads-- {
                fmt.Println("wait for thread")
                ok := <-waiters
                fmt.Printf("received thread end: %b\n", ok)
        }
}

这是运行时的日志:

push entry
push entry
push entry
entry cap: 3
waiters cap: 1
start worker
threads started: 1
wait for thread
worker: name1
worker: name2
worker: name3
throw: all goroutines are asleep - deadlock!

1 个答案:

答案 0 :(得分:5)

简单回答:您需要关闭queue

如果频道关闭,双接收运算符将仅返回false,这是您永远不会做的。所以循环过程永远不会退出。顺便说一句,你可以用频道上的for / range替换你的for / if / break。

你应该考虑其他一些Go成语:你读过http://golang.org/doc/effective_go.html吗?