I don't understand the problems 100%, but maybe these things can point you in the right direction:
- try to see if using a sync.WaitGroup{} can help you. WaitGroups are great to use when you need to keep track of a varying bunch of Go routines. - you can send channels over channels, to wait for things to happen. In pseudo-pseudo-code: type myThing struct { quit chan chan struct{} } func (m *myThing) Quit() { q := make(chan struct{}) m.quit <- q <- q } elsewhere: for { select { case <-somewhere: // do something. case q := <- m.quit: // tell all Go routines to quit and wait for that. Maybe using a WaitGroup close(q) } } On Wed, Jul 13, 2016 at 6:28 PM, Evan Digby <evandi...@gmail.com> wrote: > Hi All, > > I'm looking for some advice on a pattern I've found myself trapped in. I > don't think I like it. > > For all examples, assume I have to meet the following interface (enforced > externally): > > type DoerCloser interface { > Do() > Close() > } > > > The code below is mostly snippets from: > > https://play.golang.org/p/RQp97u4ZeK > > First, the part that seems standard (or is this my first incorrect > assumption?): > > I'm using a "closed" (or "closing") channel to tell all methods on a > struct that the user has asked us to close, and then a "done" channel to > allow the methods to alert that they're done. > > func (t *doerCloser) do() { > t.doneDoing = make(chan struct{}) > defer close(t.doneDoing) > for { > select { > case <-t.closed: > return > case <-time.After(time.Second): > fmt.Println("Doing a thing!") > } > } > } > > func (t *doerCloser) Close() { > close(t.closed) > <-t.doneDoing > } > > This works fine if the "New" function that creates the struct kicks off > the action, and therefore the "doneDoing" channel is always created and in > a good state. > > func NewDoerCloser1() DoerCloser { > dc := &doerCloser{ > closed: make(chan struct{}), > } > go dc.do() > return dc > } > > User can do the following safely: > > dc := NewDoerCloser1() > defer dc.Close() > > > Where it gets tricky is if "Do" can't be kicked off right away. In my > current real-world example I need to meet an external interface, and the > interface dictates that "Do" kicks of the thing--in other examples perhaps > you simply want the user to be able to explicitly start the doing. > > // If "do" is never called, Close will "Block" because it's a nil channel > func NewDoerCloser2() DoerCloser { > return &doerCloser{ > closed: make(chan struct{}), > } > } > > If "do" is never called, then "Close" will block forever on: > > <-t.doneDoing. > > One solution would be to create "doneDoing" and then close it immediately. > Seems crazy to me; however, It's fairly simple so perhaps it isn't crazy? > > func NewDoerCloser3() DoerCloser { > doneDoing := make(chan struct{}) > defer close(doneDoing) > > return &doerCloser{ > closed: make(chan struct{}), > doneDoing: doneDoing, > } > } > > Another solution would be to "kick off" the "Do" functionality, but have > it wait to start processing until "Do" is explicitly called. This seems > much more complex than the "create and close immediately" idea. > > func NewDoerCloser() DoerCloser { > dc := &doerCloser{ > closed: make(chan struct{}), > doCalled: make(chan struct{}), > } > > go dc.do() > > return dc > } > > func (t *doerCloser) do() { > t.doneDoing = make(chan struct{}) > defer close(t.doneDoing) > > select { > case <-t.closed: > return > case <-t.doCalled: > } > > // Let's start doing! > > for { > select { > case <-t.closed: > return > case <-time.After(time.Millisecond): > fmt.Println("Doing a thing!") > } > } > } > > > https://play.golang.org/p/qA3_oFF_EP > > Any other options? Am I totally crazy? Is this overcomplicated and there > is a much simpler solution I'm spacing on? > > Thank's everyone! > > Evan > > -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to golang-nuts+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.