Например, следующая программа правильна:
Process 0 Process 1
--------- ---------
MPI_Init(); MPI_Init();
MPI_Send(dest=1); MPI_Recv(src=0);
MPI_Finalize(); MPI_Finalize();
Без соответствующего приема информации программа ошибочна:
Process 0 Process 1
----------- -----------
MPI_Init(); MPI_Init();
MPI_Send (dest=1);
MPI_Finalize(); MPI_Finalize();
Успешный возврат из блокирующей операции связи или из MPI_WAIT или MPI_TEST говорит пользователю о том, что буфер может быть использован заново, и означает, что связь осуществлена пользователем, но не гарантирует, что у локального процесса нет больше работы. Успешный возврат из MPI_REQUEST_FREE с дескриптором, сгенерированным MPI_ISEND, обнуляет дескриптор, но не дает никакой уверенности в завершенности операции. MPI_ISEND завершен, только когда какими-либо средствами будет выяснено, что соответствующий прием информации завершен. MPI_FINALIZE гарантирует, что все локальные действия, требуемые соединениями, осуществленными пользователем, будут, в действительности, произведены до возврата из подпрограммы.
MPI_FINALIZE ничего не гарантирует относительно ожидающих соединений (завершение подтверждается только вызовом MPI_WAIT, MPI_TEST или MPI_REQUEST_FREE, вместе с другими средствами проверки завершения).
Пример Данная программа правильна:
rank 0 rank 1
=====================================================
... ...
MPI_Isend(); MPI_Recv();
MPI_Request_free(); MPI_Barrier();
MPI_Barrier(); MPI_Finalize();
MPI_Finalize(); exit();
exit();
Пример Данная программа ошибочна и ее поведение неопределено:
rank 0 rank 1
=====================================================
... ...
MPI_Isend(); MPI_Recv();
MPI_Request_free(); MPI_Finalize();
MPI_Finalize(); exit();
exit();
Если не происходит MPI_BUFFER_DETACH между MPI_BSEND (или другой буферизованной отправкой) и MPI_FINALIZE, то MPI_FINALIZE неявно поддерживает MPI_BUFFER_DETACH.
Пример Данная программа правильна, и после MPI_Finalize, она ведет
себя так, как
если бы буфер был отсоединен.
rank 0 rank 1
=====================================================
... ...
buffer = malloc(1000000); MPI_Recv();
MPI_Buffer_attach(); MPI_Finalize();
MPI_Bsend(); exit();
MPI_Finalize();
free(buffer);
exit();
Пример В данном примере подпрограмма MPI_Iprobe() должна возвращать флаг false (ложь). Подпрограмма MPI_Test_cancelled() должна возвращать флаг true(истина), независимо от относительного порядка выполнения MPI_Cancel() в процессе 0 и MPI_Finalize() в процессе 1.
Вызов MPI_Iprobe() здесь для того, чтобы убедиться, что реализация знает,
что сообщение ``tag1'' существует в месте назначения, в то время как мы не
можем утверждать, что об этом знает пользователь.
rank 0 rank 1
========================================================
MPI_Init(); MPI_Init();
MPI_Isend(tag1);
MPI_Barrier(); MPI_Barrier();
MPI_Iprobe(tag2);
MPI_Barrier(); MPI_Barrier();
MPI_Finalize();
exit();
MPI_Cancel();
MPI_Wait();
MPI_Test_cancelled();
MPI_Finalize();
exit();
Совет разработчикам: Реализации может быть нужно отложить возврат из MPI_FINALIZE, пока не будут произведены все потенциальные будущие отмены сообщений. Одним из важных решений является установка барьера в MPI_FINALIZE. []
После того как осуществляется возврат из MPI_FINALIZE, не может быть вызвана ни одна подпрограмма MPI (даже MPI_INIT), кроме MPI_GET_VERSION, MPI_INITIALIZED, и MPI-2 функции MPI_FINALIZED. Каждый процесс должен завершить все ожидающие соединения, которые он инициировал, перед вызовом MPI_FINALIZE. Если вызов возвращается, каждый процесс может продолжать локальные вычисления или завершиться без участия в дальнейших MPI соединениях с другими процессами. MPI_FINALIZE - коллективная над MPI_COMM_WORLD.
Совет разработчикам: Несмотря на то, что процесс завершил все соединения, которые он инициировал, некоторые соединения могут быть незавершены с точки зрения MPI системы. Например, блокирующая отправка может быть завершена, даже если данные все еще буферизованны у отправителя. Реализация MPI должна убеждаться, что процесс завершил все, связанное с MPI соединениями, перед возвратом из MPI_FINALIZE. Поэтому, если процесс завершается после вызова MPI_FINALIZE, это не станет причиной сбоя текущих соединений. []
Хотя и не требуется, чтобы все процессы осуществляли возврат из MPI_FINALIZE, требуется, чтобы как минимум процесс 0 в MPI_COMM_WORLD осуществлял возврат, чтобы пользователи могли знать, что вычисления MPI завершены. Кроме того, в среде POSIX, желательно поддерживать коды завершения для каждого процесса, который осуществляет возврат из MPI_FINALIZE.
Пример Следующий пример иллюстрирует использование требования, чтобы
как минимум один процесс осуществлял возврат и чтобы среди этих процессов был
процесс 0. Нужен код типа следующего для работы независимо от того, сколько
процессов осуществляют возврат.
...
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
...
MPI_Finalize();
if (myrank == 0) {
resultfile = fopen("outfile","w");
dump_results(resultfile);
fclose(resultfile);
}
exit(0);