与通道和goroutine同步

huangapple go评论102阅读模式
英文:

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 ?

huangapple
  • 本文由 发表于 2013年5月27日 04:23:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/16763384.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定