How to handle this?

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

How to handle this?

Bob Brown

Hmmm….I WAS going to write a groovymag article using GPARS.

 

But then I discovered that I wasn’t half as clever as I thought L

 

Hence, I seek enlightenment…

 

Consider the common children’s party game of pass-the-parcel:

 

There is a ring of children.

There is a parcel wrapped in multiple layers of paper.

The parcel is given to one child.

Music starts; while the music is playing, the  parcel is passed from child to child in one direction around the ring of children.

When the music stops, the child holding the parcel unwraps a layer.

If the removed layer reveals the present, the child is the winner and gets to keeps the present. Otherwise the parcel will be passed on when the music restarts.

 

My initial thought here was to use DataFlowBroadcast to broadcast the music to child tasks, and model the ring of children using DataFlowQueues.

 

With this idea a child receives either a StopMusic broadcast message OR a Parcel via a queue. I believe that one can use select to determine which message has been received.

 

So far so good.

 

Here’s where my knickers really get twisted…

 

I also have this ‘rule’: when a child receives a parcel it considers it for a short, random period of time before passing it on (in the hope that the music will stop while it has the parcel).

 

So: while the child is handling the Parcel reception, it needs to interact with a Considerer that accepts a StartConsideringTheParcel message, waits a bit and then issues a ParcelConsidered response.

The child needs to send a StartConsideringTheParcel message to the Considerer and then stay ‘awake’ to either the ParcelConsidered or StopMusic messages.

 

I have been having trouble modelling this using either Actors or Dataflow.

 

(for instance...the child cannot easily remain ‘live’ to StopMusic while still handling a Parcel. Also if the StopMusic arrives before the ParcelConsidered message, the latter has to be ‘drained’ or the Considerer task won’t be ‘live’ to any subsequent StartConsideringTheParcel message [if dataflow is being used])

 

I’m sure I could knock up some ghastly state-table driven ‘creature’ but is there a clean solution?

 

And I thought it was going to be simple…maybe it is old-age advancing.

 

Hope that all makes sense…

 

Thoughts/suggestions gratefully accepted.

 

Cheers,

 

BOB

 

---

Bob Brown

Director, Transentia Pty. Ltd.

Training, consulting, development at the leading edge of technology.

 

    73 Frasers Rd.                Mobile: 0416-078-813

    Ashgrove                      Email: [hidden email]

    Brisbane                      Web: www.transentia.com.au

    Queensland 4060

    Australia

 

NOTE: This email may NOT be taken to constitute an agreement to form a

"prior relationship" or to give "prior affirmative consent" for the

purposes of opt-in mass marketing.

 

---

 

"Electricity made us angels 

   and money made us fools, 

 but fear of future shackled us

   to gods who ride the backs of mules."

 -- Bill Nelson

 

Reply | Threaded
Open this post in threaded view
|

RE: How to handle this?

Bob Brown
I guess I am after an equivalent to CSP's

ALT
    music.stopped.channel ? x
        -- do something
    time ? AFTER now + consideration.time
        -- do something in the timeout case
     
Couldn't see an equivalent construct or a way to create such a thing.

Trying to avoid using CSP.

Cheers,

BOB


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: How to handle this?

Vaclav
Administrator
Hi Bob,

I like your story a lot. Very entertaining!
Now back the the children taking their time before passing the present on, have you considered calling the getVal(timeout, units) method on the music.stopped.channel? I guess this could do the job. Otherwise we could simulate the timer with a dedicated timer task and a channel:

//inside the child process when holding a present
def timerQueue = new DataflowVariable()
timer.schedule([run:{timerQueue << 'Pass it on'}] as TimerTask, randomDelay)  //shared java.util.Timer instance
def select = select([musicStopChannel, timerQueue])
def msg = select()
if (msg.index==0) //music stopped
else //pass the present on

Since we're using a new timerQueue each time, we don't need to care about the active timer if the music stops during the timeout period.

Regards,

Vaclav


On Tue, May 17, 2011 at 12:35 PM, Bob Brown <[hidden email]> wrote:
I guess I am after an equivalent to CSP's

ALT
   music.stopped.channel ? x
       -- do something
   time ? AFTER now + consideration.time
       -- do something in the timeout case

Couldn't see an equivalent construct or a way to create such a thing.

Trying to avoid using CSP.

Cheers,

BOB


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email





--
E-mail: [hidden email]
Blog: http://www.jroller.com/vaclav
Linkedin page: http://www.linkedin.com/in/vaclavpech
Reply | Threaded
Open this post in threaded view
|

RE: How to handle this?

Bob Brown
> I like your story a lot. Very entertaining!

Thanks.

>  have you considered calling the getVal(timeout, units) method on the
music.stopped.channel? I guess this could do the job.

I didn't know about this. Is it documented? The only reference I found was
http://hamletdarcy.blogspot.com/2010/02/testing-asynchronous-code-with-gpars
.html

Thanks for the suggestions.

> Otherwise we could simulate the timer with a dedicated timer task and a
channel:
> ...
> Since we're using a new timerQueue each time, we don't need to care about
the active timer if the music stops during the timeout period.

Good idea.

I've put together something like:

---
@Immutable final class ANY {}
final ANY = new ANY()

def considerTimerQ = {->
    def timerQueue = new DataFlowVariable<ANY>()
    def delay = ThreadLocalRandom.current().nextLong(400, 500)
    timer.schedule([run: {timerQueue << ANY}] as TimerTask, delay)
    timerQueue
}

...

def select = select([musicStopChannel, considerTimerQ()])
---

This works.

It still leaves me with a logical problem: if sometime after I do the above
select, a message appears on musicStopChannel, the next time I call select
it will return index == 0 immediately.

Is there any way to unconditionally 'drain'/reset the channel? I don't want
to do musicStopChannel.val because this is blocking...but I do want to say
"I don't care to know any value that might be left unconsumed on the
channel, only what appears after now.."

Maybe a peek() method is needed? I shuddered when I typed that...as a
general rule of concurrent programming "this way lies madness."

I feel like I am "fighting the paradigm" here...a broadcast channel might
not be the thing to use. Maybe just a global AtomicInteger (or the new STM
stuff?) might be better.

The difference is: using the channels means that I am looking for start/stop
EVENTS (I wouldn't be listening to the music's VALUE after all...), but with
an atomic integer I would be continually checking the state of the music and
this also feels wrong...

Cheers,

BOB


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: How to handle this?

Vaclav
Administrator


It still leaves me with a logical problem: if sometime after I do the above
select, a message appears on musicStopChannel, the next time I call select
it will return index == 0 immediately.

Shouldn't it be only the child with the present that is concerned about the music stop event? That way the music.stop channel could well be a DataflowQueue and children could pass it around together with the present. Whoever reads the stop mesage from the channel, he will unpack the present. If he gets a timeout, he'll pass the present together with the music.stop channel on to the next child.


Is there any way to unconditionally 'drain'/reset the channel? I don't want
to do musicStopChannel.val because this is blocking...but I do want to say
"I don't care to know any value that might be left unconsumed on the
channel, only what appears after now.."

Maybe a peek() method is needed? I shuddered when I typed that...as a
general rule of concurrent programming "this way lies madness."

The poll() method could be your friend here. It reads the next message or returns null if none is present at the moment.

I feel like I am "fighting the paradigm" here...a broadcast channel might
not be the thing to use. Maybe just a global AtomicInteger (or the new STM
stuff?) might be better.

The difference is: using the channels means that I am looking for start/stop
EVENTS (I wouldn't be listening to the music's VALUE after all...), but with
an atomic integer I would be continually checking the state of the music and
this also feels wrong...


I feel like passing the music channel around could be the most convenient way to go here. That way you never get useless messages that need to be cleared off the broadcasting channels.

Cheers,

Vaclav

Reply | Threaded
Open this post in threaded view
|

RE: How to handle this?

Bob Brown
Hi Vaclav,

> Shouldn't it be only the child with the present that is concerned about
the
> music stop event? That way the music.stop channel could well be a
> DataflowQueue and children could pass it around together with the present.
> Whoever reads the stop mesage from the channel, he will unpack the
> present. If he gets a timeout, he'll pass the present together with the
> music.stop channel on to the next child.

That IS probably a better way of doing this.

I was so intent on 'playing' with the DataFlowBroadcast feature that this
didn't occur to me.

Thanks again.

In self-defence, however: I also had in my mind the children' game of
"Musical Chairs" (as a follow-on 'project' building on this one) and in that
case the DataFlowBroadcast would be extremely useful because for this game
all the children DO need to hear the music at the same time. But in this
case, they would all clear their message as well, so this problem probably
would not present itself.

>
> The poll() method could be your friend here. It reads the next message or
> returns null if none is present at the moment.

Also a really good suggestion. Also (sorry to sound like a broken record):
is it documented? Couldn't find it mentioned in the one-page HTML...
 
>
> I feel like passing the music channel around could be the most convenient
> way to go here. That way you never get useless messages that need to be
> cleared off the broadcasting channels.

A definite possibility.

MANY Thanks.

BOB


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: How to handle this?

Vaclav
Administrator

That IS probably a better way of doing this.

I was so intent on 'playing' with the DataFlowBroadcast feature that this
didn't occur to me.

Thanks again.

In self-defence, however: I also had in my mind the children' game of
"Musical Chairs" (as a follow-on 'project' building on this one) and in that
case the DataFlowBroadcast would be extremely useful because for this game
all the children DO need to hear the music at the same time. But in this
case, they would all clear their message as well, so this problem probably
would not present itself.


I'm happy to have helped you. Examples like yours help me imagine potential GPars usage scenarios better. Please, keep them coming.
 
Also a really good suggestion. Also (sorry to sound like a broken record):
is it documented? Couldn't find it mentioned in the one-page HTML...

Indeed, the tutorial is very brief when describing the channels. I'll need to put more effort into it.
For now, perhaps the API doc could help you, when in doubts - http://gpars.org/SNAPSHOT/javadoc/groovyx/gpars/dataflow/DataflowReadChannel.html

Cheers,

Vaclav



--
E-mail: [hidden email]
Blog: http://www.jroller.com/vaclav
Linkedin page: http://www.linkedin.com/in/vaclavpech