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.

Reply via email to