Multithreading OpenMP中进程间通信的线程
我有一个OpenMP并行程序,看起来像:Multithreading OpenMP中进程间通信的线程,multithreading,parallel-processing,openmp,Multithreading,Parallel Processing,Openmp,我有一个OpenMP并行程序,看起来像: [...] #pragma omp parallel { //initialize threads #pragma omp for for(...) { //Work is done here } } 现在我正在添加MPI支持。我需要的是一个线程来处理通信,在我的例子中,它始终调用Gathere并填充/清空一个链表,以便从其他进程接收/发送数据。在设置标志之前,该线程应该发送/接收。所以现在这个示例中没有MPI内容,我的问题是关于Op
[...]
#pragma omp parallel
{
//initialize threads
#pragma omp for
for(...)
{
//Work is done here
}
}
现在我正在添加MPI支持。我需要的是一个线程来处理通信,在我的例子中,它始终调用Gathere并填充/清空一个链表,以便从其他进程接收/发送数据。在设置标志之前,该线程应该发送/接收。所以现在这个示例中没有MPI内容,我的问题是关于OpenMP中该例程的实现。
如何实现这样一个线程?例如,我尝试在这里引入一个指令:
[...]
int kill=0
#pragma omp parallel shared(kill)
{
//initialize threads
#pragma omp single nowait
{
while(!kill)
send_receive();
}
#pragma omp for
for(...)
{
//Work is done here
}
kill=1
}
但在这种情况下,程序会被卡住,因为for循环后的隐式屏障会等待上面while循环中的线程
谢谢你,鲁格米尼。你可以尝试在你的
单个结构中添加nowait
子句:
编辑:响应第一条评论
如果为OpenMP启用嵌套并行,则可以通过两级并行实现所需的功能。在顶层,您有两个并发并行部分,一个用于MPI通信,另一个用于本地计算。最后一部分本身可以并行化,这为您提供了第二级并行化。只有执行此级别的线程才会受到其中的屏障的影响
#包括
#包括
int main()
{
int kill=0;
#pragma-omp平行截面
{
#pragma-omp段
{
while(kill==0){
/*管理MPI通信*/
}
}
#pragma-omp段
{
#pragma-omp并行
#pragma omp for
对于(int i=0;i<10000;++i){
/*你的工作量*/
}
kill=1;
}
}
}
但是,您必须意识到,如果您没有至少两个线程,那么您的代码将被破坏,这意味着您正在打破这样的假设,即代码的顺序版本和并行版本应该做同样的事情
将OpenMP内核封装在更全局的MPI通信方案中(可能使用异步通信将通信与计算重叠)会更干净。Hmmm。如果您确实在程序中添加MPI“支持”,那么您应该使用mpi\u allgather
,因为mpi\u gatherall
不存在。请注意,mpi\u allgather
是一个集合操作,即通信器中的所有进程都调用它。你不能让一个进程收集数据,而让其他进程做任何事情。您可以使用MPI单边通信来实现您的想法;这将有点棘手,但如果一个进程只读取其他进程的内存,则不会比这更棘手
我对你使用的术语“线程”wrt MPI感到困惑。我担心您混淆了OpenMP和MPI,其中一种变体叫做OpenMPI。尽管有这个名字,它和OpenMP的区别就像粉笔和奶酪的区别一样。MPI程序是根据进程而不是线程编写的。典型的OpenMP实现确实使用线程,尽管程序员通常很好地隐藏了细节
您正在尝试或似乎正在尝试在OpenMP代码中使用MPI,这给我留下了深刻的印象。这与我所做的工作正好相反,我看到其他人在一些非常大的计算机上所做的工作。这种“混合”并行化的标准模式是编写调用OpenMP代码的MPI程序。今天的许多大型计算机实际上是多核盒的集合。对其中一个进行编程的典型方法是在每个框上运行一个MPI进程,并且每个进程对框中的每个核心使用一个OpenMP线程。您必须小心,因为您不能让您的MPI调用线程“跳过”omp for循环;线程团队中的所有线程都必须通过for循环
有两种方法可以做到这一点:使用嵌套的parallism和tasks,可以启动一个task进行消息传递,另一个调用包含omp并行的工作例程:
#include <mpi.h>
#include <omp.h>
#include <stdio.h>
void work(int rank) {
const int n=14;
#pragma omp parallel for
for (int i=0; i<n; i++) {
int tid = omp_get_thread_num();
printf("%d:%d working on item %d\n", rank, tid, i);
}
}
void sendrecv(int rank, int sneighbour, int rneighbour, int *data) {
const int tag=1;
MPI_Sendrecv(&rank, 1, MPI_INT, sneighbour, tag,
data, 1, MPI_INT, rneighbour, tag,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);
}
int main(int argc, char **argv) {
int rank, size;
int sneighbour;
int rneighbour;
int data;
int got;
MPI_Init_thread(&argc, &argv, MPI_THREAD_FUNNELED, &got);
MPI_Comm_size(MPI_COMM_WORLD,&size);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
omp_set_nested(1);
sneighbour = rank + 1;
if (sneighbour >= size) sneighbour = 0;
rneighbour = rank - 1;
if (rneighbour <0 ) rneighbour = size-1;
#pragma omp parallel
{
#pragma omp single
{
#pragma omp task
{
sendrecv(rank, sneighbour, rneighbour, &data);
printf("Got data from %d\n", data);
}
#pragma omp task
work(rank);
}
}
MPI_Finalize();
return 0;
}
实际上,您希望single和for同时执行,并且当for完成时停止single?这正是我想要做的:每个节点一个MPI进程,每个进程多个OpenMP线程。你说得对,这是HPC代码。很抱歉将gatherall改为allgather。我想我看到了问题所在;好吧,这让人困惑。在我上面的代码中没有mpi相关的东西。我只是想提一下我提出这个问题的动机。
#include <mpi.h>
#include <omp.h>
#include <stdio.h>
void sendrecv(int rank, int sneighbour, int rneighbour, int *data) {
const int tag=1;
MPI_Sendrecv(&rank, 1, MPI_INT, sneighbour, tag,
data, 1, MPI_INT, rneighbour, tag,
MPI_COMM_WORLD, MPI_STATUS_IGNORE);
}
int main(int argc, char **argv) {
int rank, size;
int sneighbour;
int rneighbour;
int data;
int got;
const int n=14;
MPI_Init_thread(&argc, &argv, MPI_THREAD_FUNNELED, &got);
MPI_Comm_size(MPI_COMM_WORLD,&size);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
omp_set_nested(1);
sneighbour = rank + 1;
if (sneighbour >= size) sneighbour = 0;
rneighbour = rank - 1;
if (rneighbour <0 ) rneighbour = size-1;
#pragma omp parallel
{
#pragma omp master
{
sendrecv(rank, sneighbour, rneighbour, &data);
printf("Got data from %d\n", data);
}
#pragma omp for schedule(dynamic)
for (int i=0; i<n; i++) {
int tid = omp_get_thread_num();
printf("%d:%d working on item %d\n", rank, tid, i);
}
}
MPI_Finalize();
return 0;
}