Это продолжение этот мой предыдущий вопрос, для которого вывод заключался в том, что программа была ошибочной, и поэтому ожидаемое поведение было неопределенным.
Здесь я пытаюсь создать простой механизм обработки ошибок, для чего я использую запрос Irecv для пустого сообщения в качестве «дескриптора прерывания», присоединяя его к моему обычному вызову MPI_Wait
(и превращая его в MPI_WaitAny
), чтобы позволить мне разблокировать процесс 1 в случае возникновения ошибки в процессе 0, и он больше не может достичь точки, в которой он должен опубликовать соответствие MPI_Recv
.
Происходит то, что из-за внутренней буферизации сообщений MPI_Isend
может сразу завершиться успешно, и другой процесс не сможет опубликовать соответствующий MPI_Recv
. Так что уже никак не отменить.
Я надеялся, что как только все процессы вызовут MPI_Comm_free
, я смогу раз и навсегда забыть об этом сообщении, но, как оказалось, это не так. Вместо этого он доставляется на MPI_Recv
в следующем коммуникаторе.
Итак, мои вопросы:
- Это тоже ошибочная программа, или это баг в реализации MPI (Intel MPI 4.0.3)?
- Если я превращу свои
MPI_Isend
вызовы вMPI_Issend
, программа будет работать как положено - могу ли я хотя бы в этом случае быть уверенным, что программа верна? - Я изобретаю велосипед здесь? Есть ли более простой способ добиться этого?
Опять же, любой отзыв очень ценится!
#include "stdio.h"
#include "unistd.h"
#include "mpi.h"
#include "time.h"
#include "stdlib.h"
int main(int argc, char* argv[]) {
int rank, size;
MPI_Group group;
MPI_Comm my_comm;
srand(time(NULL));
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_group(MPI_COMM_WORLD, &group);
MPI_Comm_create(MPI_COMM_WORLD, group, &my_comm);
if (rank == 0) printf("created communicator %d\n", my_comm);
if (rank == 1) {
MPI_Request req[2];
int msg = 123, which;
MPI_Isend(&msg, 1, MPI_INT, 0, 0, my_comm, &req[0]);
MPI_Irecv(NULL, 0, MPI_INT, 0, 0, my_comm, &req[1]);
MPI_Waitany(2, req, &which, MPI_STATUS_IGNORE);
MPI_Barrier(my_comm);
if (which == 0) {
printf("rank 1: send succeed; cancelling abort handle\n");
MPI_Cancel(&req[1]);
MPI_Wait(&req[1], MPI_STATUS_IGNORE);
} else {
printf("rank 1: send aborted; cancelling send request\n");
MPI_Cancel(&req[0]);
MPI_Wait(&req[0], MPI_STATUS_IGNORE);
}
} else {
MPI_Request req;
int msg, r = rand() % 2;
if (r) {
printf("rank 0: receiving message\n");
MPI_Recv(&msg, 1, MPI_INT, 1, 0, my_comm, MPI_STATUS_IGNORE);
} else {
printf("rank 0: sending abort message\n");
MPI_Isend(NULL, 0, MPI_INT, 1, 0, my_comm, &req);
}
MPI_Barrier(my_comm);
if (!r) {
MPI_Cancel(&req);
MPI_Wait(&req, MPI_STATUS_IGNORE);
}
}
if (rank == 0) printf("freeing communicator %d\n", my_comm);
MPI_Comm_free(&my_comm);
sleep(2);
MPI_Comm_create(MPI_COMM_WORLD, group, &my_comm);
if (rank == 0) printf("created communicator %d\n", my_comm);
if (rank == 0) {
MPI_Request req;
MPI_Status status;
int msg, cancelled;
MPI_Irecv(&msg, 1, MPI_INT, 1, 0, my_comm, &req);
sleep(1);
MPI_Cancel(&req);
MPI_Wait(&req, &status);
MPI_Test_cancelled(&status, &cancelled);
if (cancelled) {
printf("rank 0: receive cancelled\n");
} else {
printf("rank 0: OLD MESSAGE RECEIVED!!!\n");
}
}
if (rank == 0) printf("freeing communicator %d\n", my_comm);
MPI_Comm_free(&my_comm);
MPI_Finalize();
return 0;
}
выходы:
created communicator -2080374784
rank 0: sending abort message
rank 1: send succeed; cancelling abort handle
freeing communicator -2080374784
created communicator -2080374784
rank 0: STRAY MESSAGE RECEIVED!!!
freeing communicator -2080374784
MPI_Isend
наMPI_Issend
? Или программа правильная в этом случае? 29.05.2014MPI_ISSEND
было бы правильно. Этого, безусловно, было бы достаточно. 31.05.2014