所有 MPI 通信调用都针对称为rank的实体。目前所有 MPI 实现都遵循rank等于OS 进程的解释,即不共享内存空间的实体。原则上,您可以通过制作消息标签来解决单个线程是一种解决方法(或者更确切地说是一种 hack) - 例如,尝试在MPI_ANY_TAG
没有无限循环和/或中央进程范围的调度机制的情况下实现多个线程的模拟。
在 MPI-3.0 的早期阶段有一个提议包括所谓的端点,这基本上是一种允许将一组等级分配给进程内的一组线程的机制。该提案未通过投票机制,文本需要进一步完善。
也就是说,在不使用 pt2pt 操作重新实现集体调用的情况下,以下是实现您想要的合理方法:
#pragma omp parallel shared(gbuf) private(buf,tid)
{
tid = omp_get_thread_num();
...
// Gather threads' data into the shared buffer 'gbuf'
// Data should start at gbuf[rank * num_threads * data_per_thread]
memcpy(gbuf + (rank*num_threads + tid)*data_per_thread,
buf, data_per_thread*size);
// Make sure all threads have finished copying their chunks
// then gather the data from all the other ranks
#pragma omp barrier
#pragma omp single
{
MPI_Allgather(MPI_IN_PLACE, 0, MPI_TYPE_NULL,
gbuf, num_threads*data_per_thread, data_type, comm);
}
...
}
它首先将每个线程的本地缓冲区中的数据收集buf
到全局接收缓冲区gbuf
中。在此示例中,使用的是简单memcpy
的,但如果使用的是复杂的派生数据类型,则可能会更复杂。一旦正确收集了本地数据,就可以使用就地数据MPI_Allgather
从其他进程中收集数据。该single
构造确保每个进程只有一个线程会进行全集合调用。
如果所有进程的线程数不相同,MPI_Allgatherv
则应改为使用。