Прежде всего, MPI по умолчанию не является потокобезопасным. Вам нужно будет проверить, была ли ваша конкретная библиотека скомпилирована для обеспечения безопасности потоков, а затем инициализировать MPI, используя MPI_Init_thread
вместо MPI_Init
.
Предположим, что ваш экземпляр MPI инициализирован для потокобезопасных процедур, ваш код по-прежнему не является потокобезопасным из-за состояния гонки, которое вы уже идентифицировали.
Спаривание MPI_Probe
и MPI_Recv
в многопоточной среде не поточно, это известная проблема в MPI-2: http://htor.inf.ethz.ch/publications/img/gregor-any_size-mpi3.pdf
Есть по крайней мере два возможных решения. Вы можете использовать MPI-3 MPI_Mprobe
и MPI_MRecv
или использовать блокировку/мьютекс вокруг критического кода. Это может выглядеть следующим образом:
MPI-2 раствор (с использованием мьютекса/блокировки):
int number_amount;
if (world_rank == 0) {
int *buffer = ...
int bufferSize = ...
MPI_Send(buffer, buffersize, MPI_INT, 1, 0, MPI_COMM_WORLD);
} else if (world_rank == 1) {
MPI_Status status;
int count = -1;
/* aquire mutex/lock */
MPI_Probe(0, 0, MPI_COMM_WORLD, &status);
MPI_Get_count(&status, MPI_INT, &count);
int* buffer = (int*)malloc(sizeof(int) * count);
MPI_Recv(buffer, count, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
/* release mutex/lock */
}
MPI-3 решение:
int number_amount;
if (world_rank == 0) {
int *buffer = ...
int bufferSize = ...
MPI_Send(buffer, buffersize, MPI_INT, 1, 0, MPI_COMM_WORLD);
} else if (world_rank == 1) {
MPI_Status status;
MPI_Message msg;
int count = -1;
MPI_Mprobe(0, 0, MPI_COMM_WORLD, &msg, &status);
MPI_Get_count(&status, MPI_INT, &count);
int* buffer = (int*)malloc(sizeof(int) * count);
MPI_Mrecv(buffer, count, MPI_INT, &msg, MPI_STATUS_IGNORE);
}
Вы совершенно правы, что это условие гонки, и не было никакого способа обойти это до MPI 3, с [MPI_Mprobe] (https://www.open-mpi.org/doc/v1.8/man3/MPI_Mprobe.3.php) и, возможно, MRecv , См. Например, сообщение в блоге Джеффа Сквайра (http://blogs.cisco.com/performance/mpi-forum-roundup). –