Example
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; }