8.2.1 Examples

Example 8..1   This example shows the code for a user-defined reduce operation on an int using a binary tree: each non-root node receives two messages, sums them, and sends them up. We assume that no status is returned and that the operation cannot be cancelled.

typedef struct {
   MPI_Comm comm;
   int tag;
   int root;
   int valin;
   int *valout;
   MPI_Request request;
   } ARGS;


int myreduce(MPI_Comm comm, int tag, int root, 
              int valin, int *valout, MPI_Request *request)
{
ARGS *args;
pthread_t thread;

/* start request */
MPI_Grequest_start(query_fn, free_fn, cancel_fn, NULL, request);

args = (ARGS*)malloc(sizeof(ARGS));
args->comm = comm;
args->tag = tag;
args->root = root;
args->valin = valin;
args->valout = valout;
args->request = *request;

/* spawn thread to handle request */
/* The availability of the pthread_create call is system dependent */
pthread_create(&thread, NULL, reduce_thread, args);

return MPI_SUCCESS;
}


/* thread code */
void reduce_thread(void *ptr) 
{
int lchild, rchild, parent, lval, rval, val;
MPI_Request req[2];
ARGS *args;

args = (ARGS*)ptr;

/* compute left,right child and parent in tree; set 
   to MPI_PROC_NULL if does not exist  */
/* code not shown */
...
  
MPI_Irecv(&lval, 1, MPI_INT, lchild, args->tag, args->comm, &req[0]);
MPI_Irecv(&rval, 1, MPI_INT, rchild, args->tag, args->comm, &req[1]);
MPI_Waitall(2, req, MPI_STATUSES_IGNORE);
val = lval + args->valin + rval;
MPI_Send( &val, 1, MPI_INT, parent, args->tag, args->comm );
if (parent == MPI_PROC_NULL) *(args->valout) = val;
MPI_Grequest_complete((args->request));   
free(ptr);
return;
}

int query_fn(void *extra_state, MPI_Status *status)
{
/* always send just one int */
MPI_Status_set_elements(status, MPI_INT, 1);
/* can never cancel so always true */
MPI_Status_set_cancelled(status, 0);
/* choose not to return a value for this */
status->MPI_SOURCE = MPI_UNDEFINED;
/* tag has not meaning for this generalized request */
status->MPI_TAG = MPI_UNDEFINED;
/* this generalized request never fails */
return MPI_SUCCESS;
}


int free_fn(void *extra_state)
{
/* this generalized request does not need to do any freeing */
/* as a result it never fails here */
return MPI_SUCCESS;
}


int cancel_fn(void *extra_state, int complete)
{
/* This generalized request does not support cancelling.
   Abort if not already done.  If done then treat as if cancel failed. */
if (!complete) {
  fprintf(stderr, "Cannot cancel generalized request - aborting program\n");
  MPI_Abort(MPI_COMM_WORLD, 99);
  }
return MPI_SUCCESS;
}

MPI-Standard for MARMOT