2

I'm trying to implement a "workers" system, but I'm having some issues identifying why it deadlocks itself

The code is executed by calling fillQueue()

I do not understand why my code ends up in a dealock (on process is waiting in the second line of "process()", reading from the channel "queue", while the other is waiting at the end of "fillQueue()" waiting to read from waiters.

I do not understand why it never gets the read on waiters.

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)
        }
}

Here is the log when I run it:

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!
4

1 回答 1

5

简单的回答:你需要关闭queue.

只有当通道关闭时,双重接收运算符才会返回 false,而您永远不会这样做。所以进程中的循环永远不会退出。顺便说一句,您可以在通道上用 for/range 替换您的 for/if/break。

您还应该考虑其他一些 Go 习惯用法:您阅读过http://golang.org/doc/effective_go.html吗?

于 2013-05-26T20:50:23.487 回答