尽管打开了,TryRecv 返回通道仍关闭

我正在尝试在 Go 中编写一个函数来监视通道并记录通过它发送的内容。


func monitorChannel(inChannel, outChannel reflect.Value, fid int64, cond *sync.Cond) {

    for {       

    cond.L.Lock()

    var toLog reflect.Value

    var ok bool

    for toLog, ok = inChannel.TryRecv() ; !toLog.IsValid(); { // while no value received

        if !ok {

            cond.L.Unlock()

            return

        }

        cond.Wait()

    }

    outChannel.Send(toLog)

    logMessage("a", "b", inChannel.Interface(), toLog.Interface(), fid)

    cond.L.Unlock()

}

}


这个函数应该从 inChannel 接收,记录发送的消息并通过 outChannel 发送它。由于我希望能够记录双向通道,因此我为每个要记录的通道调用此函数两次,交换 inChannel 和 outChannel。锁是为了防止两个 goroutine 在彼此之间传递消息。“fid”只是日志文件的ID。


但是当我运行以下测试代码时,我遇到了死锁:


errsIn := make(chan int64)

errsOut := make(chan int64)

cond := sync.NewCond(&sync.Mutex{})

go monitorChannel(reflect.ValueOf(errsIn), reflect.ValueOf(errsOut), fid, cond)

go monitorChannel(reflect.ValueOf(errsOut), reflect.ValueOf(errsIn), fid,  cond)

errsIn <- 1

if <-errsOut != 1 {

    t.Fatal("lost value through channel send")

}

errsOut <- 1

if <-errsIn != 1 {

    t.Fatal("lost value through channel send")

}

即使我没有关闭通道,TryRecv 似乎在其第二个返回值上返回 false。为什么是这样?我该怎么办?


我在 Windows 8 64 位上运行 go 1.0.3。


烙印99
浏览 149回答 1
1回答

手掌心

基于反射的解决方案太复杂了,我无法弄清楚,懒惰,如果它是正确的或可行的。(我怀疑不是,但只是凭直觉。)我会以一种更简单但非通用的方式来完成这项任务。让我们有一个通道,一些生产者将使用它来写入它,一些消费者将使用它来读取它。c := make(chan T, N)可以使用一个小的辅助函数来监视这个频道,例如:func monitored(c chan T) chan T {&nbsp; &nbsp; &nbsp; &nbsp; m := make(chan T, M)&nbsp; &nbsp; &nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for v := range c {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m <- v&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; logMessage(v)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; close(m)&nbsp; &nbsp; &nbsp; &nbsp; }()&nbsp; &nbsp; &nbsp; &nbsp; return m}现在足以:mc := monitored(c)和传递c给生产者,但mc传递给消费者。c完成后关闭以免泄漏 goroutine。警告:上面的代码根本没有经过测试。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go