Overview and system design CX documentation and sample code Publications People How to contact us
[CX tutorial]
Step 1: Creating the decompose task
After stating the problem at the overview, let's continue with the construction of the decompose task. This task should implement the following functionality:
  • if the sole input argument num is less than 2, don't do any decomposition. Instead, evaluate fib(num) (where num=0 or 1) and return the results.
  • else, decompose the fib(num) into two tasks fib(num-1) and fib(num-2), and create an additional one, that will take care of the composition part (namely, the addition of the intermediate results of fib(num-1) and fib(num-2)).
Before you proceed any further, make sure you have read the CX API, that explains how a task interacts with the CX environment through the TaskContainer interface.

Here is how it looks like :
 

public class FibTaskSpawn extends CXTask {

   // required constructor!
  public FibTaskSpawn(TaskHeader taskHeader) {
      super(taskHeader);
   }

   // custom constructor(s)
   public FibTaskSpawn(int num)
    {
      //construct your task info
      //in some cases this can be more complicated
      //but it always follows the pattern bellow:

      myTaskInfo=new TaskInfo();
      myTaskInfo.isLocal=false; //even though you can make it local
      myTaskInfo.taskType=CXConst.readyTask; //meaning ready to go, all input arguments are present

      inputArguments=new Integer[1];
      inputArguments[0]=new Integer(num);
      missingInputArguments=0;

      outputDestination=new DestinationRecord[1]; //there is only one return argument

    }

   // that's the only method you must override
  public void executeTask(TaskContainer ts)
    {
       // that's the only method application programmer needs to overwrite

       // first, get the (sole) input argument, which in out case is the number
       // of the fibonucci function that we wish to evaluate, i.e. fib(num)
       Integer fibNumber=(Integer) inputArguments[0];

       int fnum=fibNumber.intValue();
       System.out.println("FibTaskSpawn:"+fnum);

       if (fnum<2)
         {
           // if the fibonucci number is less than 2,
           // then I can do the calculations without spawning new tasks ...

           TaskInfo taskInfo;
           Sequence computedBy=new Sequence(myTaskInfo.taskId);
           long jobId;
           long argPos;
           Integer[] result=new Integer[1];

           if (outputDestination[0]!=null)
           // this means that the results are intermediate, and must be returned to another task - not the consumer
             {
               taskInfo=new TaskInfo(outputDestination[0].destinationTask);
               argPos=outputDestination[0].inArgPos;
               jobId=taskInfo.jobId;
             }
           else
             {
            // results are final - should be forwarder to consumer
               taskInfo=null;
               jobId=myTaskInfo.jobId;
               argPos=0;
             }

           // now populate the result object that will be returned to your Task Container
           result[0]=new Integer(fnum); //or whatever the result might be
           Result res=new Result(taskInfo,computedBy,argPos,result);
           res.jobId=jobId;

           // send the newly created results to your task container
           ts.storeResults(res);

         }
        else
         {
           // Instead of evaluating the fib(num) functions, you create three new tasks:
           // Task t1, that corresponds to fib(num-1)
           // Task t2, that corresponds to fib(num-2)
           // Task ct, that will combine that results of the above tasks, i.e. will execute the fib(num-1)+fib(num-2) opertation

           Task t1=new FibTaskSpawn(fnum-1);
           Task t2=new FibTaskSpawn(fnum-2);
           Task ct=new FibTaskCombine();

           // Configure new tasks
           TaskInfo nti=new TaskInfo(myTaskInfo);
           nti.taskId.jobId=myTaskInfo.jobId;
           Sequence oldSeq=new Sequence(nti.taskId);

           // start with the "combine" task ...
           nti.isLocal=true; // should be executed within my Task Container ?
           nti.taskType=CXConst.waitingTask; // should wait for some input arguments, or it is ready to go?
           nti.taskId=getNextSeqNum(oldSeq,1);
           ct.setTaskInfo(nti);

           if (outputDestination[0]!=null)
            {
              ct.setOutputDestination(0,outputDestination[0].destinationTask,outputDestination[0].inArgPos);
            }
           else
            {
              ct.setOutputDestination(0,null,0);
            }

           // now, fill in the arguments for fib(num-1) task ...
           nti.taskId=getNextSeqNum(oldSeq,2);
           nti.isLocal=false; //can be executed outside the current TS
           nti.taskType=CXConst.readyTask; //ready to go!
           t1.setTaskInfo(nti);
           t1.setOutputDestination(0,ct.getTaskInfo(),0); // that will be the first input argument of ct task

           // fill in the arguments for fib(num-2) task ...
           nti.taskId=getNextSeqNum(oldSeq,3);
           nti.isLocal=false; //can be executed outside the current TS
           nti.taskType=CXConst.readyTask; //ready to go!
           t2.setTaskInfo(nti);
           t2.setOutputDestination(0,ct.getTaskInfo(),1); // that will be the second input argument of ct task

           // send the newly created tasks to your task container
           ts.storeTask(ct);
           ts.storeTask(t1);
           ts.storeTask(t2);

         }

    }
}

Make sure that you always:
  • include the required constructor, with TaskHeader as an input parameter
  • you overwrite the executeTask method, in order to do something useful.
Of course, in addition to those, you can add as many constructors/methods as you like.


For questions and comments about CX project:cappelo@cs.ucsb.edu 
For questions and comments about this site:mourlouk@cs.ucsb.com
site last updated: 01/09/2000.