Task Programming Overview - Maple Help
For the best experience, we recommend viewing online help using Google Chrome or Microsoft Edge.

# Online Help

###### All Products    Maple    MapleSim

MapleCreateContinuationTask

Create a continuation task

Description

 • This page shows two examples of using the Task Programming Model in C.
 • The examples given here implement the algorithms as Examples 2 and 3 on the examples,Task page.

Add

 • This example implements a parallel Add function.  This function implements the same algorithm as Example 2 from the examples,Task page.

C code

 #include "maplec.h" typedef struct { /* The MKernelVector is needed in the tasks */ MKernelVector kv; /* The continuation function sums the two values computed by its two children */ ALGEB left, right; } AddContArg; /* Mark the values from the left and right children, if they have been computed */ void MarkAddContFunction( void *a ) { AddContArg *args; args = (AddContArg*)a; if ( args->left != NULL ) MapleGcMark( args->kv, args->left ); if ( args->right != NULL ) MapleGcMark( args->kv, args->right ); } /* The continuation function, sum the values from the two children */ int AddTaskContFunction( void *p, int arg_number, void *a ) { AddContArg *args; args = (AddContArg*)a; switch( arg_number ) { case MAPLE_TASK_ROOT: /* If arg_number is 0, then parent is the value passed into MapleStartRootTask */ *(ALGEB*)p = MapleNumericAdd( args->kv, args->left, args->right ); break; case 1: /* If arg_number is 1, then we update the left field of our parent struct. */ ((AddContArg*)p)->left = MapleNumericAdd( args->kv, args->left, args->right ); break; case 2: /* If arg_number is 2, then we update the right field of our parent struct. */ ((AddContArg*)p)->right = MapleNumericAdd( args->kv, args->left, args->right ); break; } free( args ); return 1; } /* The worker task take a range as the argument */ typedef struct { MKernelVector kv; M_INT start, end; } AddTaskArg; /* The main task function */ int AddTaskFunction( void *p, int arg_number, void *a ) { AddTaskArg *args; args = (AddTaskArg*)a; /* check the size of the range, if it is big, divide range in half and create tasks for the two new ranges. */ if ( args->end - args->start > 1000 ) { M_INT mid; AddTaskArg *newargs; AddContArg *cont; mid = (args->end - args->start)/2 + args->start; newargs = (AddTaskArg*)malloc( sizeof( AddTaskArg ) ); cont = (AddContArg*)malloc( sizeof( AddContArg ) ); newargs->start = args->start; newargs->end = mid; args->start = mid + 1; cont->kv = newargs->kv = args->kv; cont->left = cont->right = NULL; /* create the continuation task, to sum the results of the two child tasks. */ MapleCreateContinuationTask( args->kv, AddTaskContFunction, cont, MarkAddContFunction ); /* create the child tasks, there are not garbage collectable bits in the task struct, so no Mark function is required */ MapleStartChildTask( args->kv, 1, AddTaskFunction, newargs, NULL ); MapleStartChildTask( args->kv, 2, AddTaskFunction, args, NULL ); } else { M_INT i, t; /* compute the sum over this range */ t = args->start; for ( i = args->start+1; i <= args->end; i++ ) { t += i; } switch ( arg_number ) { case MAPLE_TASK_ROOT: /* if this is the root task, then p is the value passed into MapleStartRootTask  */ *(ALGEB*)p = ToMapleInteger( args->kv, t ); break; case 1: /* if arg_number is 1, them we assign the computed value to the left field of the parent struct */ ((AddContArg*)p)->left = ToMapleInteger( args->kv, t ); break; case 2: /* if arg_number is 2, them we assign the computed value to the right field of the parent struct */ ((AddContArg*)p)->right = ToMapleInteger( args->kv, t ); break; } free( args ); } return 1; } /* The main entry point for this algorithm */ EXP_DECL ALGEB LANG_STDCALL StartAddTask( MKernelVector kv, ALGEB args ) { AddTaskArg *arg; ALGEB ret; /* create the root task */ arg = (AddTaskArg*)malloc( sizeof(AddTaskArg) ); arg->kv = kv; arg->start = MapleToM_INT( kv, MapleExpseqSelect( kv, args, 1 ) ); arg->end = MapleToM_INT( kv, MapleExpseqSelect( kv, args, 2 ) ); MapleStartRootTask( kv, &ret, AddTaskFunction, arg, NULL, NULL, 0 ); return ret; }

Mandelbrot

 • This example implements a parallel Mandelbrot generator.  This Mandelbrot generator implements the same algorithm as Example 3 from the examples,Task page.

C code

 struct MandelStruct { /* The MKernelVector is needed in the tasks */ MKernelVector kv; /* X and Y are shared among tasks, but used as read only */ double *X, *Y; /* output is shared among tasks, but areas of the table are only written to by one task */ ALGEB output; /* the 2D boundaries of the area this task is responsible for */ M_INT xLow, xHigh; M_INT yLow, yHigh; /* some parameters used in the final computation */ M_INT iter; double bailout; }; /* need to mark the output array */ void MarkMandelStruct( void *a ) { struct MandelStruct *arg = (struct MandelStruct*)a; MapleGcMark( arg->kv, arg->output ); } /* a utility function used for creating the task structures */ struct MandelStruct* NewMandelStruct( struct MandelStruct *old, M_INT xL, M_INT xH, M_INT yL, M_INT yH ) { struct MandelStruct *newArgs; newArgs = (struct MandelStruct*)malloc( sizeof( struct MandelStruct ) ); newArgs->X = old->X; newArgs->Y = old->Y; newArgs->output = old->output; newArgs->kv = old->kv; newArgs->bailout = old->bailout; newArgs->iter = old->iter; newArgs->xLow = xL; newArgs->xHigh = xH; newArgs->yLow = yL; newArgs->yHigh = yH; return newArgs; } /* the main task function */ int MandelTaskFunction( void *parent, int arg_number, void *self ) { M_INT w,h; struct MandelStruct *args; /* unused */ parent = NULL; arg_number = 0; args = (struct MandelStruct*)self; w = args->xHigh - args->xLow; h = args->yHigh - args->yLow; /* check the area of the region, if too large divide it up */ if ( w * h > 100 ) { struct MandelStruct *newArgs1,*newArgs2,*newArgs3; /* create the task structures for the child tasks */ newArgs1 = NewMandelStruct( args, args->xLow, w/2+args->xLow, args->yLow, h/2+args->yLow ); /* update the current task structure so it can be reused*/ args->xLow = newArgs1->xHigh+1; args->yLow = newArgs1->yHigh+1; newArgs2 = NewMandelStruct( args, newArgs1->xLow, newArgs1->xHigh, args->yLow, args->yHigh ); newArgs3 = NewMandelStruct( args, args->xLow, args->xHigh, newArgs1->yLow, newArgs1->yHigh ); /* create a continuation task that does not do anything */ MapleCreateContinuationTask( args->kv, NULL, NULL, NULL ); /* start the child tasks  */ MapleStartChildTask( args->kv, 1, MandelTaskFunction, newArgs1, MarkMandelStruct ); MapleStartChildTask( args->kv, 2, MandelTaskFunction, newArgs2, MarkMandelStruct ); MapleStartChildTask( args->kv, 3, MandelTaskFunction, newArgs3, MarkMandelStruct ); MapleStartChildTask( args->kv, 4, MandelTaskFunction, args, MarkMandelStruct ); } else { /* compute the Mandelbrot set for the given region */ double Xtemp, Ytemp, Xc, Yc, Xold, Yold, tmp; M_INT k, index[3]; RTableData val; for ( w = args->xLow; w <= args->xHigh; w++ ) { for ( h = args->yLow; h <= args->yHigh; h++ ) { Xtemp = args->X[w-1]; Ytemp = args->Y[h-1]; Xc = Xtemp; Yc = Ytemp; k = 0; while ( k < args->iter ) { Xold = Xtemp; Yold = Ytemp; Xtemp = Xold*Xold-Yold*Yold+Xc; Ytemp = 2*Xold*Yold+Yc; tmp = Xtemp*Xtemp+Ytemp*Ytemp; if ( tmp >= args->bailout ) { /* update the output rtable structure */ index[0] = h; index[1] = w; index[2] = 1; val.float64 = k; RTableAssign( args->kv, args->output, index, val ); index[2] = 2; val.float64 = sqrt(tmp); RTableAssign( args->kv, args->output, index, val ); break; } ++k; } } } free( args ); } return 1; } /* the main Mandelbrot entry point */ EXP_DECL ALGEB LANG_STDCALL Mandelbrot( MKernelVector kv, ALGEB args ) { M_INT i; M_INT w, h, iter; M_INT bounds[6]; double x1, x2, y1, y2, bailout, *X, *Y; struct MandelStruct *arg; ALGEB output; RTableSettings settings; /* decode the arguments */ w = MapleToM_INT( kv, MapleExpseqSelect( kv, args, 1 ) ); h = MapleToM_INT( kv, MapleExpseqSelect( kv, args, 2 ) ); iter = MapleToM_INT( kv, MapleExpseqSelect( kv, args, 3 ) ); x1 = MapleToFloat64( kv, MapleExpseqSelect( kv, args, 4 ) ); x2 = MapleToFloat64( kv, MapleExpseqSelect( kv, args, 5 ) ); y1 = MapleToFloat64( kv, MapleExpseqSelect( kv, args, 6 ) ); y2 = MapleToFloat64( kv, MapleExpseqSelect( kv, args, 7 ) ); bailout = MapleToFloat64( kv, MapleExpseqSelect( kv, args, 8 ) ); /* pre-compute the points */ X = (double *)malloc( sizeof( double )*w ); for ( i = 0; i < w; i++ ) { X[i] = x1 + (x2-x1)*(i-1)/(w-1); } Y = (double *)malloc( sizeof( double )*h ); for ( i = 0; i < h; i++ ) { Y[i] = y1 + (y2-y1)*(i-1)/(h-1); } /* create the root task */ arg = (struct MandelStruct*)malloc( sizeof( struct MandelStruct ) ); arg->X = X; arg->Y = Y; /* create the output rtable */ RTableGetDefaults( kv, &settings ); settings.data_type = RTABLE_FLOAT64; settings.num_dimensions = 3; bounds[0] = 1; bounds[1] = h; bounds[2] = 1; bounds[3] = w; bounds[4] = 1; bounds[5] = 2; arg->output = output = RTableCreate( kv, &settings, NULL, bounds ); arg->xLow = 1; arg->xHigh = w; arg->yLow = 1; arg->yHigh = h; arg->iter = iter; arg->bailout = bailout; arg->kv = kv; /* start the root task */ MapleStartRootTask( kv, NULL, MandelTaskFunction, arg, MarkMandelStruct, NULL, 0 ); free( X ); free( Y ); return output; }