//------------------------------------------------------------------------------ /** @file ring_mpi.cpp @brief Primer kanonickog prstena. Originalni primer je preuzet od: Open Systems Laboratory http://www.lam-mpi.org/tutorials/ Indiana University i preradjen za potrebe ovog kursa. */ //------------------------------------------------------------------------------ #include #include //------------------------------------------------------------------------------ using namespace std; //------------------------------------------------------------------------------ /** @brief Preklopljeni operator @b << . @param os Referenca na izlazni tok. @param status Status MPI rutine. @return Vraca referencu na izlazni tok. */ ostream& operator<<(ostream& os, MPI::Status& status); //------------------------------------------------------------------------------ /** @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) rank = MPI::COMM_WORLD.Get_rank(); // Trazimo velicinu MPI sveta size = MPI::COMM_WORLD.Get_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; cout << "Ovo je proces " << rank << ", u MPI svetu se nalazi izmedju procesa " << prev << " i " << next << endl; // 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) { cout << "Unesite broj krugova po MPI svetu: "; cin >> num; cout << "Proces " << rank << " salje broj " << num <<" procesu " << next << std::endl; // Saljemo ucitani broj sledecem procesu u MPI svetu MPI::COMM_WORLD.Send(&num, 1, MPI::INT, next, tag); } // 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::COMM_WORLD.Recv(&num, 1, MPI::INT, prev, tag, status); std::cout << "Proces " << rank << " je upravo primio broj " << num << " od procesa " << prev << std::endl; std::cout << "Status: " << status << std::endl; // Ako je ovaj proces 0 (master), umanji broj za 1 if (rank == 0) { --num; cout << "Process 0 (master) je upravo smanjio broj na " << num << endl; } cout << "Proces " << rank << " je upravo poslao broj " << num << " procesu " << next << endl; // Saljemo podatak sledecem u MPI svetu MPI::COMM_WORLD.Send(&num, 1, MPI::INT, next, tag); } while (num > 0); cout << "Proces " << rank << " je zavrsio sa slanjem i napusta ciklus" << endl; // 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::COMM_WORLD.Recv(&num, 1, MPI::INT, prev, tag, status); cout << "Proces 0 (master) je upravo primio poslednju poruku" << endl; cout << "Status: " << status << endl; } // Zavrsavamo MPI MPI::Finalize(); return 0; } //------------------------------------------------------------------------------ std::ostream& operator <<(ostream &os, MPI::Status& status) { os << "posiljalac " << status.Get_source() << ", oznaka " << status.Get_tag() << ", kod greske " << status.Get_error() << ", duzina poruke " << status.Get_count(MPI::INT) << " podataka tipa MPI::INT"; return os; } //------------------------------------------------------------------------------