英文:
Sync with channels and goroutines
问题
我正在尝试实现一个“工人”系统,但是我遇到了一些问题,无法确定为什么会发生死锁。
通过调用fillQueue()函数来执行代码。
我不明白为什么我的代码会陷入死锁(一个进程在“process()”函数的第二行等待,从通道“queue”读取,而另一个进程在“fillQueue()”函数的末尾等待从waiters通道读取。
我不明白为什么它从未读取到waiters。
以下是运行代码时的日志:
推入条目
推入条目
推入条目
条目容量:3
等待者容量:1
启动工人
已启动的线程数:1
等待线程
工人:name1
工人:name2
工人:name3
抛出:所有goroutine都处于休眠状态-死锁!
英文:
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!
答案1
得分: 5
简单回答:你需要关闭queue
。
双向接收操作符只有在通道关闭时才会返回false,而你从未关闭它。因此,process中的循环永远不会退出。顺便说一下,你可以用for/range遍历通道来替代你的for/if/break。
还有一些其他的Go语言习惯用法你应该考虑一下:你读过http://golang.org/doc/effective_go.html吗?
英文:
Simple answer: You need to close queue
.
The dual receive operator will only return false iff the channel is closed, which you never do. So the loop in process never exits. Incidentally you can replace your for/if/break with a for/range over a channel.
There are a few other Go idioms that you should consider: have you read http://golang.org/doc/effective_go.html ?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论