Я внимательно осмотрелся вокруг, но не смог найти ссылки на эту проблему.
Я написал программу на C ++, которую я тестирую с помощью boost / unit. Серийная версия работает нормально, а модульный тест работает.
Теперь я сделал программу параллельной с помощью функции, выполняющей смущающе параллельную работу с MPI. Если записать мой собственный тест, вызывающий параллельную функцию — назовем это парафункцией — он работает хорошо, MPI работает нормально.
Компиляция выполняется с помощью mpic ++, и я использую mpixec для запуска программы.
Однако, если я вызываю функцию parafunction в тестовом буст-тесте, MPI работает неправильно, тест запускается несколько раз и происходит сбой процесса, когда несколько MPI::Init
называются.
Вот пример ошибки, которую я получаю:
Функция MPI_comm_size () была вызвана после вызова MPI_FINALIZE.
Это запрещено стандартом MPI.
Ваша работа MPI теперь будет прервана.
Мой тестовый пример находится в test_unit, автоматически обрабатываемом master_test_suite. Как я уже сказал, без распараллеливания это работает на отлично.
Парафункция звонков MPI::Init
а также MPI::Finalize
и никакая другая функция файлов не должна выполнять какие-либо вещи, связанные с MPI.
Кто-нибудь сталкивался с подобной проблемой раньше?
Мой тестовый прогон довольно длинный, поэтому я действительно мог бы использовать параллельную версию моей программы!
Спасибо за вашу помощь
Функция, которая как инициализирует, так и завершает, может быть вызвана только один раз, потому что MPI может быть инициализирован только один раз за время существования программы и может быть завершен только один раз. Чтобы предотвратить множественные вызовы инициализации, поместите вызов в MPI_Init()
или же MPI_Init_thread()
в условном:
int already_initialised;
MPI_Initialized(&already_initialised);
if (!already_initialised)
MPI_Init(NULL, NULL);
Что касается финализации, она должна быть перемещена за пределы вашей функции, вероятно, в atexit(3)
обработчик, если вы не хотите загрязнять внешнюю область вызовами MPI. Например:
void finalise_mpi(void)
{
int already_finalised;
MPI_Finalized(&already_finalised);
if (!already_finalised)
MPI_Finalize();
}
...
atexit(finalise_mpi);
...
atexit()
вызов может быть частью кода инициализации, например:
int already_initialised;
MPI_Initialized(&already_initialised);
if (!already_initialised)
{
MPI_Init(NULL, NULL);
atexit(finalise_mpi);
}
Это не будет устанавливать atexit(3)
обработчик, если MPI уже был инициализирован. Основная идея заключается в том, что если MPI был инициализирован при входе в функцию, это будет означать, что MPI_Init()
был вызван во внешнем объеме, и можно было бы ожидать, что MPI_Finalize()
там тоже называется.
На вашем месте я бы переместил инициализацию и финализацию MPI из функции параллельной обработки. Правильная последовательность вызова будет инициализировать MPI, запустить тесты, а затем завершить MPI.
Я использовал привязки C в вышеприведенном тексте, поскольку привязки C ++ были устаревшими в MPI-2.2, а затем удалены в MPI-3.0.
Других решений пока нет …