/******************************************************************************/ /** @file "MPI/C/Primer 3 - ring/ring_mpi.c" @brief Primer kanonickog prstena. Originalni primer je preuzet od:@n @n Open Systems Laboratory, Indiana University, i preradjen za potrebe ovog kursa. */ /******************************************************************************/ #include #include /******************************************************************************/ /** @brief Glavni program @param argc Broj argumenata komandne linije. @param argv Argumenti komandne linije. @return Vraca @b 0 ako je sve uspesno izvrseno. */ int main(int argc, char* argv[]) { MPI_Status status; int num, rank, size, tag, next, prev; /* MPI inicijalizacija */ MPI_Init(&argc, &argv); /* Trazimo svoj poredak unutar MPI sveta (prvi je 0) */ MPI_Comm_rank(MPI_COMM_WORLD, &rank); /* Trazimo velicinu MPI sveta */ MPI_Comm_size(MPI_COMM_WORLD, &size); /* Izaberemo 201 kao oznaku naseg programa (mada moze i neka druga vrednost). Izracunamo rank prethodnog i sledeceg procesa u prstenu. Koristimo operator % kako bi mogli da kruzimo po rednim brojevima poredaka u MPI svetu. */ tag = 201; prev = (rank + size - 1) % size; next = (rank + 1) % size; printf("Ovo je proces %d, u MPI svetu se nalazi izmedju procesa %d i %d\n", rank, prev, next); /* Ako smo glavni proces, na konzoli, ucitamo ceo broj sa standardnog ulaza kako bi odredili koliko puta zelimo da obidjemo prsten (MPI svet) */ if (rank == 0) { printf("Unesite broj krugova po MPI svetu: "); scanf("%d", &num); printf("Proces %d salje broj %d procesu %d\n", rank, num, next); /* Saljemo ucitani broj sledecem procesu u MPI svetu */ MPI_Send(&num, 1, MPI_INT, next, tag, MPI_COMM_WORLD); } /* Prosledjujemo poruku kroz prsten. Izlazni mehanizam radi po sledecem principu: poruka (pozitivni ceo broj) se prosledjuje kroz prsten. Svaki put kada prodje cvor sa rangom 0, dekrementira se. Kada svaki proces primi poruku koja se sastoji od broja 0, prosledjuje poruku sledecem procesu i zavrsava se. Prosledjivanjem nule kao prve poruke, svaki proces prima nulu i normalno se zavrsava. Ukratko: sve dok je broj koji prosledjujemo od procesa do procesa veci od 0, setamo ga po MPI svetu. */ do { if (rank == 0 && num == 0) break; /* Cekamo da primimo podatak od prethodnog u MPI svetu */ MPI_Recv(&num, 1, MPI_INT, prev, tag, MPI_COMM_WORLD, &status); printf("Proces %d je upravo primio broj %d od procesa %d\n", rank, num, prev); printf("Status: posiljalac %d, oznaka %d, kod greske %d\n", status.MPI_SOURCE, status.MPI_TAG, status.MPI_ERROR); /* Ako je ovaj proces 0 (master), umanji broj za 1 */ if (rank == 0) { --num; printf("Process 0 (master) je upravo smanjio broj na %d\n", num); } printf("Proces %d je upravo poslao broj %d procesu %d\n", rank, num, next); /* Saljemo podatak sledecem u MPI svetu */ MPI_Send(&num, 1, MPI_INT, next, tag, MPI_COMM_WORLD); } while (num > 0); printf("Proces %d je zavrsio sa slanjem i napusta ciklus\n", rank); /* Poslednji proces ima jedno slanje vise - procesu 0, koji mora da primi tu poruku, kako bi se program zavrsio */ /* Proces 0 (master) prima poruku od sebi prethodnog (poslednjeg u MPI svetu) */ if (0 == rank) { MPI_Recv(&num, 1, MPI_INT, prev, tag, MPI_COMM_WORLD, &status); printf("Proces 0 (master) je upravo primio poslednju poruku\n"); printf("Status: posiljalac %d, oznaka %d, kod greske %d\n", status.MPI_SOURCE, status.MPI_TAG, status.MPI_ERROR); } /* Zavrsavamo MPI */ MPI_Finalize(); return 0; } /******************************************************************************/