für das Zusammenspiel von MPI_Keyval_create, copy_fn, delete_fn und den Funktionen für Attribute. Der vordefinierte Kommunikator MPI_COMM_WORLD wird mit einem Attribut versehen und dann mit MPI_Comm_dup kopiert. Da in delete_fn das flag gesetzt wird, wird das Attribut in den neuen Kommunikator kopiert und dort wieder abgerufen.
#include "mpi.h"
#include <stdio.h>
static int keyval=MPI_KEYVAL_INVALID;
typedef struct {
int refcnt;
char arch[20];
int master;
} attribute_t;
int copy_fn(MPI_Comm *comm, int *keyval, void *extra_state ,
attribute_t *attribute_val_in, attribute_t **attribute_val_out,
int *flag);
int delete_fn(MPI_Comm *comm, int *keyval, attribute_t *attribute_val,
void *extra_state );
void glob_sum(MPI_Comm comm, int data, int *sum);
void init_data(int *data);
int main(int argc, char *argv[]) {
int myid, numprocs, i, res, data;
attribute_t *attribute_val;
MPI_Comm comm, comm2;
MPI_Copy_function *copy_ptr;
MPI_Delete_function *delete_ptr;
if (MPI_Init(&argc, &argv)!=MPI_SUCCESS) {
fprintf( stderr,"MPI_Init failed.\n");
return -1;
}
if (MPI_Keyval_create(
(MPI_Copy_function *)& copy_fn,
(MPI_Delete_function *)&delete_fn,
&keyval, (void *)0)!=MPI_SUCCESS) {
fprintf(stderr,"Proc %d: insufficient keys available.\n", myid);
MPI_Finalize();
return -2;
}
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
attribute_val=(attribute_t *)malloc(sizeof(attribute_t));
attribute_val->master=numprocs-1;
attribute_val->refcnt=0;
if (myid==attribute_val->master) {
#ifdef MPI_LINUX
sprintf(attribute_val->arch,"LINUX");
#else
sprintf(attribute_val->arch,"NO_LINUX");
#endif
}
MPI_Bcast(&attribute_val->arch, 10, MPI_CHAR,
attribute_val->master, MPI_COMM_WORLD);
MPI_Attr_put(MPI_COMM_WORLD, keyval, attribute_val);
MPI_Comm_dup(MPI_COMM_WORLD, &comm);
MPI_Comm_rank(comm, &myid);
init_data(&data);
MPI_Barrier(comm);
glob_sum(comm, data, &res);
/*if (myid==attribute_val->master) {
fprintf(stderr,"Proc %d: Global sum %d\n", myid, res);
}*/
MPI_Comm_free(&comm);
MPI_Keyval_free(&keyval);
MPI_Finalize();
}
int copy_fn(MPI_Comm *comm, int *keyval, void *extra_state ,
attribute_t *attribute_val_in, attribute_t **attribute_val_out,
int *flag) {
attribute_val_in->refcnt += 1;
*flag=1;
*attribute_val_out=(attribute_t *)malloc(sizeof(attribute_t));
memcpy(*attribute_val_out, attribute_val_in, sizeof(attribute_t));
return MPI_SUCCESS;
}
int delete_fn(MPI_Comm *comm, int *keyval, attribute_t *attribute_val,
void *extra_state) {
attribute_val->refcnt -= 1;
free((void *) attribute_val);
return MPI_SUCCESS;
}
void glob_sum(MPI_Comm comm, int data, int *sum) {
attribute_t *attr;
int master, flag, myid;
MPI_Attr_get(comm, keyval, &attr, &flag);
if (flag) {
master=attr->master;
MPI_Comm_rank(comm, &myid);
fprintf(stderr,"Proc%d: master %d is running on a %s-System (%d)\n",
myid, attr->master, attr->arch, attr->refcnt);
}
else {
master=0;
}
/* Beispiel für irgendeine Operation, die das Attribut nutzt */
MPI_Reduce(&data, sum, 1, MPI_INT, MPI_SUM, master, comm);
}
void init_data(int *data) {
/* irgendeine Initialisierung - nur Simulation für Nutzdaten */
int me;
MPI_Comm_rank( MPI_COMM_WORLD, &me);
*data=me+1;
}
| Makefile | C-Quelltext |