Programowanie równoległe i współbieżne |
|
Ćwiczenie: Ćwiczenie 4 |
Data oddania: 15.4.2013 |
Imię, Nazwisko: Kulecka Aleksandra |
Ocena: |
Uwagi:
|
Cel ćwiczenia
Celem ćwiczenia było zapoznanie się z komunikacją punktową w MPI na podstawie dwóch sposób przesyłania komunikatu (ping-pong oraz token).
Kod źródłowy wraz z objaśnieniem
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include "mpi.h"
using namespace std;
int main( int argc, char *argv[] )
{
int rank, dest;
int size;
int inmsg, tag = 1;
int rc, source;
MPI_Status Stat;
MPI_Init( 0, 0 );
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
int count = 2;
if(rank == 0)
{ dest = rank + 1;
source = size - 1;
inmsg = 0;
for (int i = 0; i < count; i++ )
{
rc = MPI_Send(&inmsg,1,MPI_INT,dest,tag,MPI_COMM_WORLD);
cout << "Proces " << rank << " wyslano do " << dest <<" liczbe " <<inmsg <<endl;
inmsg += 1;
rc = MPI_Recv(&inmsg,1,MPI_INT,source,tag,MPI_COMM_WORLD,&Stat);
cout << "Proces " << rank << " odebrano od " << source <<" liczbe " <<inmsg<<endl;
}
}else if(rank == (size-1))
{
source = rank - 1;
dest = 0;
for (int i = 0; i < count; i++ )
{
rc = MPI_Recv(&inmsg,1,MPI_INT,source,tag,MPI_COMM_WORLD,&Stat);
cout << "Proces " << rank << " odebrano od " << source <<" liczbe " <<inmsg<<endl;
inmsg += 1;
rc = MPI_Send(&inmsg,1,MPI_INT,dest,tag,MPI_COMM_WORLD);
cout << "Proces " << rank << " wyslano do " << dest <<" liczbe " <<inmsg <<endl;
}
}else
{
source = rank - 1;
dest = rank + 1;
for (int i = 0; i < count; i++ )
{
rc = MPI_Recv(&inmsg,1,MPI_INT,source,tag,MPI_COMM_WORLD,&Stat);
cout << "Proces " << rank << " odebrano od " << source <<" liczbe " <<inmsg<<endl;
inmsg += 1;
rc = MPI_Send(&inmsg,1,MPI_INT,dest,tag,MPI_COMM_WORLD);
cout << "Proces " << rank << " wyslano do " << dest <<" liczbe " <<inmsg <<endl;
}
}
MPI_Finalize();
return 0;
}
Kolorem żółtym oznaczono fragment, w którym załączam 4 podstawowe biblioteki, służące do wykorzystywania charakterystycznych poleceń w programie (np. polecenie cout, cin, MPI_Send,...).
Kolorem jasnozielonym oznaczono linijkę, dzięki której, wykorzystanie poleceń z biblioteki iostream, nie musi zostać poprzedzone każdorazowo odnośnikiem do klasy std (std::cout, std::cin).
Błękitnym kolorem oznaczono deklarację/definicję zmiennych lokalnych, przechowujących rozmiar, treść, źródło, tag, cel oraz inne parametry komunikatu wysyłanego za pomocą MPI między procesami.
Różowy kolor oznacza zadeklarowanie zmiennych charakterystycznych dla MPI takich jak status komunikatu, początek pętli przesyłania, wielkość oraz rozmiar komunikatu.
Niebieski kolor oznacza deklarację i definicje zmiennej lokalnej oznaczającej ile razy komunikat będzie przesłany.
W zależności od numeru procesu, który aktualnie jest rozpatrywany przez program (kolor czerwony) wykonywane jest pewne polecenie.
Jeśli jest to proces początkowy (rank ==0), to zwiększony staje się numer procesu (komunikat będzie wysyłany do kolejnego procesu), źródło z którego komunikat w procesie początkowym został odebrany, jest równy wielkości procesu - 1 (numeracja rozpoczyna się od 0! ). Następnie za przesyłaną wiadomość podstawia się wartość początkową równą 0. W pętli for, od 0 do licznika (zadeklarowanego w niebieskim oznaczeniu), wykonują się następujące czynności:
Za zmienną rc podstawiony zostaje wynik funkcji MPI_Send (wiadomość wysłana), które przyjmuje za zmienne treść komunikatu do wysłania, zmienną typu MPI_INT, kierunek, do którego wysyła się komunikat, tag komunikatu, oraz wielkość samego procesu.
Następnie zostaje wypisana na ekran informacja o wysłaniu komunikatu oraz jego treści, źródle i odbiorcy.
Wiadomość zostaje zwiększona o 1.
Ponownie za zmienną rc podstawiany jest rezultat działa funkcji MPI_Recv (wiadomość odebrana), który przyjmuje następujące argumenty: odebrany komunikat,treść, zmienną typu MPI_INT, źródło komunikatu, tag, wielkość procesu oraz aktualny status.
Wyświetlona zostaje informacja o odebraniu komunikatu ze źródłem, treścią komunikatu oraz odborcy.
Jeśli proces nie jest procesem początkowym, a końcowym, wówczas, za źródło przyjmuje się wielkość procesu - 1 (numeracja następuje od 0!), odbiorcą (czy przeznaczeniem komunikatu) jest proces początkowy - 0, a następnie zostaje wykonana pętla for o dokładnie takim samym działaniu jak w pierwszym przyadku (odebranie wiadomości, zapisanie stanu do zmiennej, wyświetlenie informacji o postępie, zwiększenie komunikatu, wysłanie komunikatu, wypisanie informacji o wysłaniu).
Jeśli natomiast proces znajduje się pomiędzy początkiem a końcem (i nie jest ani początkiem, ani końcem), wówczas za źródło podstawiana wielkość procesu - 1, za przeznaczenie wielkość
procesu + 1, a dopiero później wykonywana jest pętla for.
Polecenie MPI_Finalize(); zamyka pętlę przesyłania komunikatu.
Polecenie return 0; zwraca wartość 0 z funkcji głównej main.