我正在使用MPI_Probe
动态发送消息(接收方不知道正在发送的消息的大小)。我的代码看起来有点像这样 -
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_Probe(0, 0, MPI_COMM_WORLD, &status);
int count = -1;
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);
}
如果我在多个线程中运行此代码,是否有可能在一个线程中调用MPI_Probe
并且由于调度程序交错线程而在另一个线程中调用MPI_recv
。从本质上讲,上面的代码是线程安全的。
答案 0 :(得分:4)
首先,MPI默认情况下不是线程安全的。您必须检查您的特定库是否已针对线程安全进行编译,然后使用MPI_Init_thread
而不是MPI_Init
初始化MPI。
假设您的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);
}