javamultithreadinggroovygpars

How to terminate all slave actors via master actor in GPars?


I'd like to have my master actor terminate all slave actors as soon as the first one finishes its work.
However, I have no idea how I could send a broadcast from my master to all the slaves. Is there a function or programming pattern for this?

Another way to solve this problem could be to give the master a list of all slaves and loop through them, sending each a message to terminate, however the slaves also need the master as an attribute and I think this is a problem:

import groovyx.gpars.actor.Actor
import groovyx.gpars.actor.DefaultActor

class Slave extends DefaultActor {
    Actor master
    int t

    void act() {
        t = new Random().nextInt(1337)
        println "It's me, $t"
        master.send 0
    }

}

class Master extends DefaultActor {
    List slaves 

    void afterStart() {
        println "Master initialized!"
    }

    void killTheSlaves() {
        for (i in 0..slaves.size()-1){
            slaves[i].send -1
        }
    }

    void act() {
        react { int num ->
            if (num == 0)
                killTheSlaves()
        }
    }
}

def sl = new Slave().start()

def ma = new Master(slaves: [sl]).start()
sl.master = ma

This code does not compile.
Error message:

An exception occurred in the Actor thread Actor Thread 2 java.lang.NullPointerException: Cannot invoke method send() on null object at org.codehaus.groovy.runtime.NullObject.invokeMethod(NullObject.java:91) at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:48) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) at org.codehaus.groovy.runtime.callsite.NullCallSite.call(NullCallSite.java:35) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) at Slave.act(ConsoleScript14:11) at groovyx.gpars.actor.DefaultActor.handleStart(DefaultActor.java:342) at groovyx.gpars.actor.AbstractLoopingActor$1.handleMessage(AbstractLoopingActor.java:70) at groovyx.gpars.util.AsyncMessagingCore.run(AsyncMessagingCore.java:132) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745)

Looks like I cannot set sl.master after I created the slave.

Is there a workaround for this?

Any help is greatly appreciated.
Thank you in advance!


Solution

  • You should first setup the actors and then start them: def sl = new Slave() def ma = new Master(slaves: [sl]) sl.master = ma sl.start() ma.start()

    However, your Slave actors finish by themselves by running out of their act() method before the master even attempts to kill them, so no killing the slaves is actually needed.

    GPars offers a terminate() method on actors to kill them gracefully, so you might consider changing your method to: void killTheSlaves() { for (i in 0..slaves.size()-1){ slaves[i].terminate() } }