0

I have an application where one goroutine will eventually compute a value and at that point any number of routines waiting for that value need to continue execution. This a one-to-many communication problem so I struggled with channels and condition variables by keeping track of how many routines were waiting. Moreover, I wanted the broadcast to be non-blocking and future waits to return immediately since the value is known.

I ended up with the following implementation where closing the channel effectively broadcasts the group, since the write happens before any of the reads there should not be any races. Although works great so far seems a bit hackish to me. Is there a more idiomatic yet simple solution to this problem?

type BroadcastGroup struct {
    ch      chan interface{}
    msg     interface{}
}

func (bg *BroadcastGroup) Broadcast(msg interface{}) {
    bg.msg = msg
    close(bg.ch)
}

func (bg *BroadcastGroup) Wait() interface{} {
    <-bg.ch
    return bg.msg
}

func NewBroadcastGroup() *BroadcastGroup {
    bg := &BroadcastGroup{}
    bg.ch = make(chan interface{}, 0)
    return bg
}
  • 1
    Can you give an example of how you use this, and what the question about its usage is? This just seems like a simplified conditional, as the channel could be replaced with a mutex and accomplish the same. – JimB Mar 05 '18 at 21:07
  • The very same discussion: https://stackoverflow.com/questions/36417199/how-to-broadcast-message-using-channel – alexey_p Mar 05 '18 at 21:18
  • It is part of a consensus algorithm. Several clients can be waiting for the same index position to be committed. Once the algorithm decides they all need to continue. Could you elaborate on the mutex solution? – Jose Javier Gonzalez Ortiz Mar 05 '18 at 21:19
  • 3
    It sounds like what you want may be a [`sync.Cond`](https://golang.org/pkg/sync/#Cond). – Adrian Mar 05 '18 at 21:47
  • @JoseJavierGonzalezOrtiz: I only mean that here you're using a channel as a mutex, with the only difference of not being able to re-lock it (which may be fine, since if it's invalid to broadcast again, this will conveniently panic). Though if you were going to want to make this re-entrant, you probably would end up using a `sync.Cond` anyway. Without the full context we can't really say if there is a simpler pattern, this is pretty simple as it is. – JimB Mar 05 '18 at 22:41
  • Possible duplicate of [Go: One producer many consumers](https://stackoverflow.com/questions/16930251/go-one-producer-many-consumers) – Michael Hampton Mar 06 '18 at 00:05
  • I implemented one day something similar [here](https://github.com/vardius/message-bus) maybe help you solve your thoughts – vardius Mar 06 '18 at 02:55

0 Answers0