Il seguente esempio mostra un programma in cui n processi (in questo caso 4) si scambiano informazioni in una configurazione “ad anello”, in cui ognuno invia e riceve a/da i suoi vicini, l’utilizzo di chiamate non bloccanti è utile per evitare situazioni di deadlock.
#include "mpi.h"#include "stdio.h"int main(int argc, char *argv[]) { int num_task, rank, next, prev, buf[2], value_to_send; MPI_Request reqs[4]; MPI_Status stats[4]; MPI_Init(NULL, NULL); MPI_Comm_size(MPI_COMM_WORLD, &num_task); MPI_Comm_rank(MPI_COMM_WORLD, &rank); // Calculation of neighbors in the ring prev = (rank - 1 + num_task) % num_task; next = (rank + 1) % num_task; // Each process sends rank * 10 value_to_send = rank * 10; // Non-blocking communication with neighbors MPI_Irecv(&buf[0], 1, MPI_INT, prev, 0, MPI_COMM_WORLD, &reqs[0]); MPI_Irecv(&buf[1], 1, MPI_INT, next, 0, MPI_COMM_WORLD, &reqs[1]); MPI_Isend(&value_to_send, 1, MPI_INT, prev, 0, MPI_COMM_WORLD, &reqs[2]); MPI_Isend(&value_to_send, 1, MPI_INT, next, 0, MPI_COMM_WORLD, &reqs[3]); // --- Do computation here to overlap with communication --- int result = 0; for (int i = 0; i < 1000000; ++i) { result += rank * i; // Example: simulate computational work } // --------------------------------------------------------- // Wait for all non-blocking communications to finish MPI_Waitall(4, reqs, stats); // Print received values printf("Process %d received %d from prev (rank %d), %d from next (rank %d)\n", rank, buf[0], prev, buf[1], next); MPI_Finalize(); return 0;}
Output
Dopo aver eseguito il codice con mpirun -np 4 ./a.out, otteniamo in output:
Process 2 received 10 from prev (rank 1), 30 from next (rank 3)Process 0 received 30 from prev (rank 3), 10 from next (rank 1)Process 3 received 20 from prev (rank 2), 0 from next (rank 0)Process 1 received 0 from prev (rank 0), 20 from next (rank 2)
Nota
In questo esempio mostriamo anche che, grazie all’utilizzo delle chiamate non bloccanti MPI_Irecv e MPI_Isend, è possibile effettuare operazioni di calcolo tra l’avvio della comunicazione e la sincronizzazione finale (MPI_Waitall). In questo modo si può sovrapporre comunicazione e calcolo, ottimizzando l’efficienza del programma parallelo.