首页 > 解决方案 > 处理超时和收听频道

问题描述

我有看起来像这样的代码,我正在收听一个频道,直到超时间隔。让我们说这个 goroutine1

select {
    case <-time.After(TimeoutInterval):
        mu.Lock()
        defer mu.Unlock()
        delete(msgChMap, index)
        return ""
    case msg := <-msgCh:
        return msg
}

在其他地方,我有一个2运行类似这样的 goroutine,它msgCh从 Map 中获取适当的内容,删除 map 中的条目,然后通过通道发送消息。

mu.Lock()
msgCh, ok := msgChMap[index]
delete(msgChMap, index)
mu.Unlock()
if ok {
    msgCh <- "yay"
}

似乎我可以msgCh从 Map 中获取消息通道,尝试发送消息,但是因为TimeoutInterval已经过去,所以不会有任何东西在听该通道,并且我的代码会卡住等待侦听器。如果我在发送yay到后加锁msgCh,我可能会死锁,因为2将等待通道的侦听器并且不释放锁,但1不再侦听但需要锁。

避免等待听众卡住的一般模式是什么?也许 go 足够聪明,不会被困在这里。

标签: goconcurrencylockingchannelgoroutine

解决方案


这里的问题是频道阅读器在作者不知道的情况下停止了。应该可以构造这个解决方案,使这种情况永远不会发生,但是暂时忽略这一点,对于这个特定问题,您需要的是对通道本身的原子访问,以及通道状态的标志:

type channel struct {
   sync.Mutex

   msgCh chan Msg
   active bool
}

现在通过锁定通道来完成写入通道:

ch.Lock()
if ch.active {
   ch.msgCh<-data
}
ch.Unlock()

当您“停用”频道时,请重置标志:

    case <-time.After(TimeoutInterval):
        mu.Lock()
        defer mu.Unlock()
        ch.Lock()
        defer ch.Unlock()
        delete(msgChMap, index)
        ch.active=false
        return ""

当然,现在你必须*channel在你的地图中保留一个。


推荐阅读