Пример 6.1. Этот пример показывает код для определяемой пользователем
небольшой операции над типом int
с использованием бинарного дерева:
каждый некорневой узел получает два сообщения, суммирует их содержимое, и
посылает на уровень выше. Принимается, что никакого статуса не
возвращается и что операция не может быть отменена.
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;
/* Запрос стартует */
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;
/* Нить узла обработки запроса */
/* Доступность вызова pthread_create определяется системой */
pthread_create(&thread, NULL, reduce_thread, args);
return MPI_SUCCESS;
}
/* код нити*/
void reduce_thread(void *ptr) {
int Ichild, rchild, parent, lval, rval, val;
MPI_Request req[2];
ARGS *args;
args = (ARGS*)ptr;
/* Определение ссылкок вниз влево, вниз вправо и вверх для узла дерева; */
/* Установка в MPI_PROC_NULL если ссылки не существуют */
/* Код не показан */
...
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[l]);
MPI_Waitall(2, req, \verb|MPI_STATUSES_IGNORE|) ;
val = Ival + 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 \verb|query_fn|(void *extra_state, MPI_Status *status) {
/* Всегда посылает только int */
MPI_Status_set_elements (status, MPI_INT, 1);
/* Никогда нельзя отменить т.к. всегда истинна */
MPI_Status_set_cancelled(status, 0);
/* Выбрано, что для этого ничего не возвращается */
status->MPI_SOURCE = MPI_UNDEFINED;
/* Тэг не имеет смысла для этого обобщенного запроса */
status->MPI_TAG = MPI_UNDEFINED;
/* Этот обобщенный запрос всегда выполняется */
return MPI_SUCCESS;
}
int \verb|free_fn|(void *extra_state) {
/* Этот обобщенный запрос не требует никакого освобождения т.к. всегда
выполняется */
return MPI_SUCCESS;
}
int cancel_fn(void *extra_state, int complete) {
/* Этот обобщенный запрос не поддерживает отмену. */
/*Выход Ц, если уже выполнен. */
/*Если выполнен, то нить такая же, как и для случая с отменой. */
if (!complete) {
fprintf (stderr,
"Cannot cancel generalized request - aborting
program\n"); MPI_Abort(MPI_COMM_WORLD, 99);
}
return MPI_SUCCESS;
}