Solution Fiche TD 5 (MPI)
Exercice 1 : Hello World distribué
#include <stdio.h>
#include <mpi.h>
int main(int argc, char *argv[]) {
// Initialisation de l'environnement MPI
MPI_Init(&argc, &argv);
// Récupération du rang du processeur (ID) et du nombre total de processeurs
int rang, np;
MPI_Comm_rank(MPI_COMM_WORLD, &rang); // Récupère le rang du processeur courant
MPI_Comm_size(MPI_COMM_WORLD, &np); // Récupère le nombre total de processeurs
// Affichage du message pour chaque processeur
printf("Bonjour, je suis le processeur %d parmi %d processeurs\n", rang, np);
// Finalisation de l'environnement MPI
MPI_Finalize();
return 0;
}
Exercice 2 : Somme parallèle
Paritie 1 : En utilisant seulement MPI_Send et MPI_Recv
Chaque processeur initialise une variable entière égale à son rang, et le processeur maître (le
processeur 0) doit calculer la somme de ces valeurs en utilisant les fonctions MPI_Send et MPI_Recv
pour envoyer et recevoir les données :
#include <stdio.h>
#include <mpi.h>
int main(int argc, char *argv[]) {
// Initialisation de l'environnement MPI
MPI_Init(&argc, &argv);
// Récupération du rang du processeur (ID) et du nombre total de processeurs
int rang, np;
MPI_Comm_rank(MPI_COMM_WORLD, &rang); // Récupère le rang du processeur courant
MPI_Comm_size(MPI_COMM_WORLD, &np); // Récupère le nombre total de processeurs
// Chaque processeur initialise sa variable avec son rang
int valeur = rang;
1
// Le processeur maître (P0) calcule la somme des valeurs
int som_total= 0;
if (rang== 0) {
som_total = valeur; // Le processeur 0 commence la somme avec sa propre valeur
// Recevoir les valeurs des autres processeurs et les ajouter à la somme
for (int i = 1; i < np; i++) {
int valeur_recue;
MPI_Recv(&valeur_recue, 1, MPI_INT, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
// 0 est Le tag est une valeur utilisée pour identifier le message (facultatif).
som_total += valeur_recue;
}
// Afficher la somme totale
printf("La somme totale des valeurs des processeurs est: %d\n", som_total);
} else {
// Les autres processeurs envoient leur valeur au processeur maître (P0)
MPI_Send(&valeur, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
}
// Finalisation de l'environnement MPI
MPI_Finalize();
return 0;
}
Remarque :
MPI_STATUS_IGNORE
Type : MPI_Status *status
Ce paramètre donne des informations sur la réception, telles que l'identité du processeur qui a envoyé
le message et le tag du message. Ici, nous utilisons MPI_STATUS_IGNORE car nous n'avons pas besoin
de ces informations supplémentaires. Cela signifie que le statut de la réception n'est pas nécessaire et
qu'il peut être ignoré.
Paritie 2 : En utilisant seulement MPI_Reduce
- Initialisation de la valeur de chaque processeur : Chaque processeur initialise une variable
entière égale à son rang.
- Utilisation de MPI_Reduce pour calculer la somme : La fonction MPI_Reduce permet de
collecter les valeurs de tous les processeurs et de les réduire (ici, les additionner) dans une
seule variable qui sera stockée sur le processeur maître (P0).
- Le processeur maître affiche le résultat : Le processeur 0 reçoit la somme totale et l'affiche.
#include <stdio.h>
#include <mpi.h>
int main(int argc, char *argv[]) {
// Initialisation de l'environnement MPI
MPI_Init(&argc, &argv);
2
// Récupération du rang du processeur (ID) et du nombre total de processeurs
int rang, np;
MPI_Comm_rank(MPI_COMM_WORLD, &rang); // Récupère le rang du processeur courant
MPI_Comm_size(MPI_COMM_WORLD, &np); // Récupère le nombre total de processeurs
// Chaque processeur initialise sa variable avec son rang
int valeur = rang;
// Variable pour stocker le résultat de la réduction (la somme totale)
int som_total = 0;
// Utilisation de MPI_Reduce pour calculer la somme totale sur le processeur 0
MPI_Reduce(&valeur, &som_total, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
// Le processeur maître (P0) affiche le résultat
if (rang == 0) {
printf("La somme totale des valeurs des processeurs est: %d\n", som_total);
}
// Finalisation de l'environnement MPI
MPI_Finalize();
return 0;
}
Remarque :
int MPI_Reduce(
const void *sendbuf, // Buffer d'envoi (données à envoyer depuis chaque processeur)
void *recvbuf, // Buffer de réception (résultat de la réduction, reçu par le processeur racine)
int count, // Nombre d'éléments à réduire
MPI_Datatype datatype, // Type de donnée
MPI_Op op, // Opération de réduction (par exemple, somme, maximum, etc.)
int root, // Rang du processeur racine (où le résultat sera stocké)
MPI_Comm comm // Communicateur (généralement MPI_COMM_WORLD)
);
Exercice 3 : Diffusion avec MPI_Bcast
- Initialiser une valeur entière sur le processeur maître (P0).
- Diffuser cette valeur à tous les autres processeurs en utilisant MPI_Bcast.
- Afficher la valeur reçue sur chaque processeur.
- Étendre le programme pour que chaque processeur ajoute son rang à la valeur reçue avant
de l'afficher.
3
#include <stdio.h>
#include <mpi.h>
int main(int argc, char *argv[]) {
// Initialisation de l'environnement MPI
MPI_Init(&argc, &argv);
// Récupération du rang du processeur (ID) et du nombre total de processeurs
int rang, np;
MPI_Comm_rank(MPI_COMM_WORLD, &rang); // Récupère le rang du processeur courant
MPI_Comm_size(MPI_COMM_WORLD, &np); // Récupère le nombre total de processeurs
// Processeur maître (P0) initialise la valeur
int valeur = 0;
if (rang == 0) {
valeur = 10; // Valeur initiale définie par le maître
}
// Diffusion de la valeur à tous les autres processeurs
MPI_Bcast(&valeur, 1, MPI_INT, 0, MPI_COMM_WORLD);
// Chaque processeur ajoute son rang à la valeur reçue
valeur += rang;
// Affichage de la valeur reçue + rang pour chaque processeur
printf("Processeur %d : valeur reçue + rang = %d\n", rang, valeur);
// Finalisation de l'environnement MPI
MPI_Finalize();
return 0;
}
Exercice 4 : Calcul de la moyenne
- Initialiser un tableau d'entiers dans le processeur maître (P0).
- Utiliser MPI_Scatter pour distribuer les sous-tableaux à chaque processeur.
- Chaque processeur calcule la somme locale de ses éléments.
- Utiliser MPI_Reduce pour agréger la somme totale et calculer la moyenne sur le processeur
maître.
#include <stdio.h>
#include <mpi.h>
int main(int argc, char *argv[]) {
int rang, np;
int N = 8; // Taille du tableau (peut être changée)
int tab[N], som_local = 0, som_total = 0;
double moyenne;
// Initialisation de l'environnement MPI
4
MPI_Init(&argc, &argv);
// Récupération du rang du processeur et du nombre total de processeurs
MPI_Comm_rank(MPI_COMM_WORLD, &rang);
MPI_Comm_size(MPI_COMM_WORLD, &np);
// Initialisation du tableau sur le processeur maître (P0)
if (rang== 0) {
// Remplissage du tableau avec des valeurs (par exemple, 1 à N)
for (int i = 0; i < N; i++) {
tab[i] = i + 1; // Tableau {1, 2, 3, ..., N}
}
}
// Déterminer le nombre d'éléments par processeur (en supposant que N est divisible par le
nombre de processeur)
int n_local = N / np;
// Tableau local pour chaque processeur
int tab_local [n_local];
// Utilisation de MPI_Scatter pour distribuer les sous-tableaux aux processeurs
MPI_Scatter(tab, n_local, MPI_INT, tab_local, n_local, MPI_INT, 0, MPI_COMM_WORLD);
// Chaque processeur calcule la somme de ses éléments locaux
for (int i = 0; i < n_local; i++) {
som_local += tab_local[i];
}
// Utilisation de MPI_Reduce pour calculer la somme totale de tous les éléments
MPI_Reduce(&som_local, &som_total, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
// Le processeur maître calcule et affiche la moyenne
if (rang == 0) {
moyenne = (double)som_total / N;
printf("La somme totale est : %d\n", som_total);
printf("La moyenne est : %f\n", moyenne);
}
// Finalisation de l'environnement MPI
MPI_Finalize();
return 0;
}
Remarque :
int MPI_Scatter(
const void *sendbuf, // Buffer d'envoi (données envoyées par le processeur maître)
int sendcount, // Nombre d'éléments envoyés par processeur
MPI_Datatype sendtype, // Type des éléments envoyés
5
void *recvbuf, // Buffer de réception (les sous-tableaux reçus par chaque processeur)
int recvcount, // Nombre d'éléments reçus par processeur
MPI_Datatype recvtype, // Type des éléments reçus
int root, // Rang du processeur racine (qui envoie les données)
MPI_Comm comm // Communicateur
);
int MPI_Gather(
const void *sendbuf, // Buffer d'envoi (données envoyées par chaque processeur)
int sendcount, // Nombre d'éléments envoyés par chaque processeur
MPI_Datatype sendtype, // Type des éléments envoyés
void *recvbuf, // Buffer de réception (données collectées à partir de chaque processeur)
int recvcount, // Nombre d'éléments reçus par le processeur racine
MPI_Datatype recvtype, // Type des éléments reçus
int root, // Rang du processeur racine (qui recevra les données)
MPI_Comm comm // Communicateur
);
Exercice 5 : Tri parallèle
- Initialisation du tableau sur le processeur maître (P0) : Le tableau sera initialisé avec des
valeurs aléatoires.
- Utilisation de MPI_Scatter pour répartir les sous-tableaux entre les processeurs.
- Tri des sous-tableaux localement : Chaque processeur trie son propre sous-tableau, par
exemple, en utilisant le tri par insertion.
- Utilisation de MPI_Gather pour regrouper les sous-tableaux triés sur P0.
- Fusion finale des sous-tableaux triés sur P0 : Une fois que P0 a tous les sous-tableaux triés, il
fusionne les sous-tableaux pour obtenir un tableau complet trié.
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#define N 16 // Taille du tableau
#define ROOT 0 // Rang du processeur maître
// Fonction pour trier un tableau par insertion
void tri_insertion(int *T, int n) {
int i, key, j;
for (i = 1; i < n; i++) {
key = T[i];
j = i - 1;
while (j >= 0 && T[j] > key) {
T[j + 1] = T[j];
j = j - 1;
}
T[j + 1] = key;
}
}
// Fonction pour fusionner deux sous-tableaux triés
6
void fusionner(int *T, int *gauche, int *droite, int gauche_taille, int droite_taille) {
int i = 0, j = 0, k = 0;
while (i < gauche_taille && j < droite_taille) {
if (gauche[i] < droite[j]) {
T[k++] = gauche[i++];
} else {
T[k++] = droite[j++];
}
}
while (i < gauche_taille) {
T[k++] = gauche[i++];
}
while (j < droite_taille) {
arr[k++] = droite[j++];
}
}
int main(int argc, char *argv[]) {
int rang, np;
int tab[N], tab_local[N / 4], local_trié[N / 4], tab_groupé[N];
int taille_local = N / 4;
// Initialisation de MPI
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rang);
MPI_Comm_size(MPI_COMM_WORLD, &np);
// Initialisation du tableau sur le processeur maître (P0)
if (rang == ROOT) {
// Initialisation du tableau avec des valeurs aléatoires
for (int i = 0; i < N; i++) {
tab[i] = rand() % 100; // Valeurs aléatoires entre 0 et 99
}
// Affichage du tableau initial sur le processeur maître
printf("Tableau initial sur P0:\n");
for (int i = 0; i < N; i++) {
printf("%d ", tab[i]);
}
printf("\n");
}
// Distribution des sous-tableaux à chaque processeur via MPI_Scatter
MPI_Scatter(tab, taille_local, MPI_INT, tab_local, taille_local, MPI_INT, ROOT,
MPI_COMM_WORLD);
// Chaque processeur trie son sous-tableau local
Tri_insertion(tab_local, taille_local);
7
// Rassemblement des sous-tableaux triés sur P0 via MPI_Gather
MPI_Gather(tab_local, taille_local, MPI_INT, tab_groupé, taille_local, MPI_INT, ROOT,
MPI_COMM_WORLD);
// Le processeur maître fusionne les sous-tableaux triés
if (rang == ROOT) {
// Fusion des sous-tableaux triés
int pas = taille_local;
while (pas < N) {
for (int i = 0; i < N; i += 2 * pas) {
int mid = i + pas < N ? i + pas : N;
int fin_droite = i + 2 * pas < N ? i + 2 * pas : N;
fusionner(&tab_groupé[i], &tab_groupé[i], &tab_groupé[mid], pas, fin_droite - mid);
}
pas *= 2;
}
// Affichage du tableau trié sur P0
printf("Tableau trié sur P0:\n");
for (int i = 0; i < N; i++) {
printf("%d ", tab_groupé[i]);
}
printf("\n");
}
// Finalisation de MPI
MPI_Finalize();
return 0;
}
Exercice 6 : Barrière de synchronisation
- Initialisation de MPI : Commencer par initialiser MPI.
- Exécution d'une tâche spécifique pour chaque processeur : Chaque processeur effectue une
tâche (par exemple, calculer un nombre aléatoire ou effectuer un calcul simple).
- Synchronisation avec MPI_Barrier : Utiliser MPI_Barrier pour forcer tous les processeurs à se
synchroniser avant de passer à l'étape suivante.
- Affichage du résultat après la synchronisation : Chaque processeur peut afficher un message
pour montrer qu'il a terminé sa tâche et qu'il attend que tous les autres aient fini.
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#define N 4 // Nombre de processeur dans l'exemple
int main(int argc, char *argv[]) {
int rang, np;
int local_data;
8
// Initialisation de MPI
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rang);
MPI_Comm_size(MPI_COMM_WORLD, &np);
// Chaque processeur effectue une tâche spécifique, ici génération d'un nombre aléatoire
local_data = rand() % 100; // Génère un nombre aléatoire entre 0 et 99
// Affichage du résultat avant synchronisation
printf("Processeur %d a effectué une tâche et a généré la valeur %d.\n", rang, local_data);
// Synchronisation avec MPI_Barrier
MPI_Barrier(MPI_COMM_WORLD); // Tous les processeurs doivent attendre ici
// Tous les processeurs arrivent ici après la barrière de synchronisation
printf("Processeur %d a passé la barrière de synchronisation.\n", rang);
// Finalisation de MPI
MPI_Finalize();
return 0;
}
Exercice 7 : Produit matriciel distribué
Le programme suivant distribue les lignes de la matrice A entre les processeurs, diffuse B à tous les
processeurs, calcule localement le produit partiel, puis rassemble les résultats.
- Initialisation des matrices :
• La matrice A est répartie ligne par ligne.
• La matrice B est diffusée à tous les processeurs.
- Répartition des lignes de A avec MPI_Scatter :
• Chaque processeur reçoit une portion de A correspondant à un groupe de lignes.
- Diffusion de B avec MPI_Bcast :
• Tous les processeurs reçoivent la matrice complète B pour effectuer les calculs.
- Calcul local :
• Chaque processeur calcule sa portion de C, qui est le produit des lignes reçues de A avec
la matrice B.
- Rassemblement des résultats avec MPI_Gather :
• Les résultats calculés par chaque processeur sont rassemblés dans la matrice finale C.
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#define N 4 // Taille des matrices (N x N)
9
void afficher_matrice(int matrice[N][N], int lignes, int colonnes, const char *nom) {
printf("Matrice %s:\n", nom);
for (int i = 0; i < lignes; i++) {
for (int j = 0; j < colonnes; j++) {
printf("%d ", matrice[i][j]);
}
printf("\n");
}
printf("\n");
}
int main(int argc, char *argv[]) {
int rang, np;
int A[N][N], B[N][N], C[N][N]; // Matrices A, B et C
int A_local[N][N], C_local[N][N]; // Lignes locales de A et portion de C
MPI_Init(&argc, &argv);
MPI_Comm_rang(MPI_COMM_WORLD, &rang);
MPI_Comm_size(MPI_COMM_WORLD, &np);
// Vérification que la division des lignes est possible
if (N % np != 0) {
if (rang == 0) {
printf("Erreur : le nombre de lignes (%d) n'est pas divisible par le nombre de processeurs
(%d).\n", N, np);
}
MPI_Finalize();
return EXIT_FAILURE;
}
int lignes_par_proc = N / np; // Nombre de lignes par processeurs
// Initialisation des matrices sur P0
if (rang == 0) {
// Remplir la matrice A et B avec des valeurs arbitraires
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
A[i][j] = i + j; // Exemple : somme des indices
B[i][j] = i * j; // Exemple : produit des indices
}
}
afficher_matrix(A, N, N, "A");
afficher_matrix(B, N, N, "B");
}
// Distribution des lignes de A avec MPI_Scatter
MPI_Scatter(A, lignes_par_proc * N, MPI_INT, A_local, lignes_par_proc * N, MPI_INT, 0,
MPI_COMM_WORLD);
// Diffusion de la matrice B à tous les processeurs
MPI_Bcast(B, N * N, MPI_INT, 0, MPI_COMM_WORLD);
10
// Calcul local du produit des lignes de A avec B
for (int i = 0; i < lignes_par_proc; i++) {
for (int j = 0; j < N; j++) {
C_local [i][j] = 0; // Initialisation
for (int k = 0; k < N; k++) {
C_local [i][j] += A_local[i][k] * B[k][j];
}
}
}
// Rassemblement des résultats dans la matrice C avec MPI_Gather
MPI_Gather(C_local, lignes_par_proc * N, MPI_INT, C, lignes_par_proc * N, MPI_INT, 0,
MPI_COMM_WORLD);
// Affichage du résultat sur P0
if (rang == 0) {
print_matrice(C, N, N, "C (produit de A et B)");
}
MPI_Finalize();
return 0;
}
Exercice 8 : Calcul de π avec la méthode de Monte Carlo
Méthode de calcul de π avec Monte Carlo :
Pour calculer π, on utilise la géométrie :
- Considérons un cercle inscrit dans un carré de côté 2r (cercle de rayon r=1 et carré de
côté 2).
- L'aire du cercle est πr2 =π.
- L'aire du carré est 4r2 =4.
L’Idée est la suivante :
- Générer des points aléatoires dans le carré [−1,1]×[−1,1].
- Compter le nombre de points qui tombent à l’intérieur du cercle (x2+y2≤1).
- La proportion de ces points dans le cercle, par rapport au nombre total de points, donne
une estimation de π : π≈4×(Points dans le cercle/Points totaux)
Les étapes du calcul :
- Générer des points aléatoires : Produire N points avec des coordonnées x,y aléatoires
entre [−1,1][-1, 1].
- Vérifier si chaque point (x,y) satisfait x2+y2≤1.
- Estimer π :
• Compter les points à l’intérieur du cercle (C).
• Approcher π avec la formule :
𝐶
𝜋 =4∗𝑁
11
- Initialisation MPI :
• Définir le nombre total de points à générer.
• Répartir les calculs entre les processeurs.
- Simulation locale :
• Chaque processeur génère une portion des points et compte combien tombent dans le
cercle.
- Réduction des résultats :
• Utiliser MPI_Reduce pour agréger les points dans le cercle de tous les processeurs.
• Le processeur maître (P0) calcule π à partir des résultats.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <mpi.h>
#include <time.h>
int main(int argc, char *argv[]) {
int rang, np;
long long int points_total = 1000000; // Nombre total de points
long long int points_par_process; // Points générés par chaque processeur
long long int nbr_local = 0; // Points dans le cercle pour ce processeur
long long int nbr_global = 0; // Total des points dans le cercle
double pi_estimee;
// Initialisation de MPI
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rang);
MPI_Comm_size(MPI_COMM_WORLD, &np);
// Diviser le travail entre les processeurs
points_par_process = points_total / np;
// Initialisation du générateur aléatoire avec une graine unique pour chaque processeur
srand(time(NULL) + rang);
// Simulation de Monte Carlo
for (long long int i = 0; i < points_par_process; i++) {
double x = (double)rand() / RAND_MAX * 2.0 - 1.0; // Coordonnée x entre -1 et 1
double y = (double)rand() / RAND_MAX * 2.0 - 1.0; // Coordonnée y entre -1 et 1
if (x * x + y * y <= 1.0) {
nbr_local++; // Point dans le cercle
}
}
// Réduction : somme des points dans le cercle
12
MPI_Reduce(&nbr_local, &nbr_global, 1, MPI_LONG_LONG_INT, MPI_SUM, 0,
MPI_COMM_WORLD);
// Calcul de π sur le processeur maître
if (rang == 0) {
pi_estimee = 4.0 * (double)nbr_global / points_total;
printf("Estimation de π avec %lld points : %f\n", points_total, pi_estimee);
}
// Finalisation de MPI
MPI_Finalize();
return 0;
}
Exercice 9 : Maximum distribué
- Initialisation : Chaque processeur initialise un tableau d'entiers avec des valeurs spécifiques.
- Calcul du maximum local : Chaque processeur trouve le maximum de son propre tableau
local.
- Réduction avec MPI_Reduce : Les maximums locaux de tous les processeurs sont réduits en
un maximum global sur le processeur maître (P0).
- Affichage : Le processeurs maître (P0) affiche le maximum global.
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#define N 5 // Taille du tableau local de chaque processeur
int main(int argc, char *argv[]) {
int rang, np;
int tab_local [N];
int max_local, max_global;
// Initialisation de MPI
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rang);
MPI_Comm_size(MPI_COMM_WORLD, &np);
// Initialisation du tableau local avec des valeurs spécifiques
for (int i = 0; i < N; i++) {
tab_local[i] = rang * N + i; // Ex : valeurs uniques pour chaque processeur
}
// Calcul du maximum local
max_local = tab_local[0];
for (int i = 1; i < N; i++) {
if (tab_local[i] > max_local) {
max_local = tab_local[i];
}
}
13
printf("Processeur %d : Maximum local = %d\n", rang, max_local);
// Réduction pour trouver le maximum global
MPI_Reduce(&max_local, &max_global, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
// Affichage du résultat par le processeur maître
if (rang == 0) {
printf("Le maximum global est : %d\n", max_global);
}
// Finalisation de MPI
MPI_Finalize();
return 0;
}
Exercice 10 : Communication en anneau
- Initialisation :
• Chaque processeur initialise une valeur à envoyer (par exemple, son rang).
- Définition des voisins :
• Le voisin suivant est (rang + 1) % np (avec size étant le nombre total de processeur).
• Le voisin précédent est (rang - 1 + np) % np.
- Communication :
• Chaque processeur envoie sa valeur au suivant en utilisant MPI_Send.
• Simultanément, il reçoit une valeur de son voisin précédent en utilisant MPI_Recv.
- Affichage des résultats :
• Chaque processeur affiche la valeur reçue.
#include <stdio.h>
#include <mpi.h>
int main(int argc, char *argv[]) {
int rang, np;
int valeur_envoyée, valeur_recue;
int suivant, précédent;
// Initialisation de MPI
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rang);
MPI_Comm_size(MPI_COMM_WORLD, &np);
// Définition des voisins dans l'anneau
suivant = (rang + 1) % np; // Voisin suivant
précédent = (rang - 1 + np) % np; // Voisin précédent
// Chaque processeur initialise une valeur à envoyer
valeur_envoyée = rang;
14
// Communication : envoyer au voisin suivant et recevoir du voisin précédent
MPI_Send(&valeur_envoyée, 1, MPI_INT, suivant, 0, MPI_COMM_WORLD);
MPI_Recv(&valeur_recue, 1, MPI_INT, précédent, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
// Affichage de la valeur reçue
printf("Processeur %d a reçu la valeur %d de son voisin %d.\n", rang, valeur_recue, précédent);
// Finalisation de MPI
MPI_Finalize();
return 0;
}
Prototypes des fonctions MPI_Send et MPI_Recv :
int MPI_Send(
const void *buf, // Pointeur vers le buffer contenant les données à envoyer
int count, // Nombre d'éléments à envoyer
MPI_Datatype datatype, // Type de données des éléments (e.g., MPI_INT, MPI_FLOAT)
int dest, // Rang du processus destinataire
int tag, // Tag du message (permet de différencier les messages)
MPI_Comm comm // Communicateur (e.g., MPI_COMM_WORLD)
);
int MPI_Recv(
void *buf, // Pointeur vers le buffer où stocker les données reçues
int count, // Nombre maximum d'éléments à recevoir
MPI_Datatype datatype, // Type de données des éléments
int source, // Rang du processus émetteur
int tag, // Tag du message
MPI_Comm comm, // Communicateur
MPI_Status *status // Statut du message (informations comme la source et le tag réel)
);
Rôle du tag dans MPI :
1. Identification des messages :
o Lorsqu'un processus envoie plusieurs types de messages à un autre, le tag permet de
les différencier.
o Le receveur peut filtrer les messages en spécifiant un tag particulier dans MPI_Recv.
15
2. Filtrage de messages :
o Si un processus receveur spécifie un tag précis dans MPI_Recv, seuls les messages
avec ce tag seront acceptés.
3. Cas général (Ignorer le tag) :
o Si le receveur ne veut pas filtrer les messages par tag, il peut utiliser la constante
spéciale MPI_ANY_TAG comme argument du paramètre tag dans MPI_Recv.
16