0% ont trouvé ce document utile (0 vote)
68 vues16 pages

Programmation MPI : Exercices Pratiques

Transféré par

bochramiinfo
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
68 vues16 pages

Programmation MPI : Exercices Pratiques

Transféré par

bochramiinfo
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

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

Vous aimerez peut-être aussi