| |
Головная программа:
main(int argc, char **argv) { int ma, mb; MPI_Group MPI_GROUP_WORLD, group_a, group_b; MPI_Comm comm_a, comm_b; static int list_a[] = {0, 1}; #if defined(EXAMPLE_2B) | defined(EXAMPLE_2C) static int list_b[] = {0, 2 ,3}; #else/* EXAMPLE_2A */ static int list_b[] = {0, 2}; #endif int size_list_a = sizeof(list_a)/sizeof(int); int size_list_b = sizeof(list_b)/sizeof(int); ... MPI_Init(&argc, &argv); MPI_Comm_group(MPI_COMM_WORLD, &MPI_GROUP_WORLD); MPI_Group_incl(MPI_GROUP_WORLD, size_list_a, list_a, &group_a); MPI_Group_incl(MPI_GROUP_WORLD, size_list_b, list_b, &group_b); MPI_Comm_create(MPI_COMM_WORLD, group_a, &comm_a); MPI_Comm_create(MPI_COMM_WORLD, group_b, &comm_b); if(comm_a != MPI_COMM_NULL) MPI_Comm_rank(comm_a, &ma); if(comm_b != MPI_COMM_NULL) MPI_Comm_rank(comm_b, &mb); if(comm_a != MPI_COMM_NULL) lib_call(comm_a); if(comm_b != MPI_COMM_NULL) { lib_call(comm_b); lib_call(comm_b); } if(comm_a != MPI_COMM_NULL) MPI_Comm_free(&comm_a); if(comm_b != MPI_COMM_NULL) MPI_Comm_free(&comm_b); MPI_Group_free(&group_a); MPI_Group_free(&group_b); MPI_Group_free(&MPI_GROUP_WORLD); MPI_Finalize(); }
Библиотека:
void lib_call(MPI_Comm comm) { int me, done = 0; MPI_Comm_rank(comm, &me); if(me == 0) while(!сделано) { MPI_Recv(..., MPI_ANY_SOURCE, MPI_ANY_TAG, comm); ... } else { /* работа */ MPI_Send(..., 0, ARBITRARY_TAG, comm); .... } #ifdef EXAMPLE_2C /* include (resp, exclude) for safety (resp, no safety): */ MPI_Barrier(comm); #endif }
Приведенный выше пример - это на самом деле три примера, зависящих от того, включен или не включен процесс номер 3 в list_b, включена или не включена синхронизация в lib_call. Пример показывает, что нет необходимости защищать друг от друга последовательные обращения к lib_call с тем же самым контекстом. Безопасность будет реализована, еcли добавлена функция MPI_Barrier. Это демонстрирует тот факт, что библиотеки должны быть тщательно разработаны, даже при наличии контекстов.
Алгоритмы с недетерминированной широковещательной операцией или другие обращения с произвольными номерами поцессов-отправителей в общем случае будут уступать детерминированным реализациям ``reduce'', ``allreduce'', и ``broadcast''. Таким алгоритмам следовало бы использовать монотонно возрастающие тэги (в пределах контекста коммуникатора), чтобы сохранить корректность вычислений.
Все предшествующее формирует гипотезу ``коллективных обращений'', реализованных на основе парных обменов. Реализации MPI могут использовать для реализации коллективных операций парные обмены, хотя это и не обязательно. Парные обмены используются здесь, чтобы иллюстрировать проблемы правильности и безопасности, независимо от того, как MPI осуществляет коллективные запросы. См. также раздел 5.8.
Закладки на сайте Проследить за страницей |
Created 1996-2024 by Maxim Chirkov Добавить, Поддержать, Вебмастеру |