棘手问题: MPI中使用pthread线程调用 MPI_Send/MPI_Recv 收发消息

donkeymeng 2012-02-27 09:20:58

#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

#define DEBUG 0

void *computingFun(void *ptr)
{
int rank, nprocs;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD,&nprocs);
if(!DEBUG) printf("proc:%d Sending Thread Start\n",rank);

unsigned long long data[3];

int root = 0;
char sendFinishTag = 1;

char *recvFinishTag;
if(rank == 0) recvFinishTag = new char [nprocs];

MPI_Gather(&sendFinishTag, 1, MPI_CHAR, recvFinishTag, 1, MPI_CHAR, root, MPI_COMM_WORLD);

if(rank==0)
{
int sum = 0;
for(int i=0; i<nprocs; i++)
sum += recvFinishTag[i];

printf("---------------------------%d\n", sum);
if(sum != nprocs)
{
printf("Gather Tags Error\n");
exit(0);
}
}
if(rank==0)
{
data[0] = rank;
data[2] = 10;
for(int i=0;i<nprocs;i++)
{
data[1] = i;

MPI_Send(data, 3, MPI_LONG_LONG_INT, i, 0, MPI_COMM_WORLD);
// if(!DEBUG) printf("|proc:%d Sending finishMsg to -[%d]-\n",rank, i);
}
}
/*
for(int i=0;i<nprocs;i++)
{
if(rank == i) continue;
data[0] = rank;
data[1] = i;
data[2] = 10; //finish msg flag

MPI_Send(data, 3, MPI_LONG_LONG_INT, i, 0, MPI_COMM_WORLD);
if(!DEBUG) printf("|proc:%d Sending finishMsg to -[%d]-\n",rank, i);
}
*/
}

void *serviceFun(void *ptr)
{
int rank, nprocs;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
if(!DEBUG) printf("proc:%d Recving Thread Start\n",rank);

char *msgFlagArray = new char [nprocs];
for(int i=0;i<nprocs;i++) msgFlagArray[i] = 0;

MPI_Status stats;
unsigned long long srcNodeID, dstNodeID, msgType;
unsigned long long data[3];

while(1)
{
MPI_Recv(data, 3, MPI_LONG_LONG_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &stats);
if(!DEBUG) printf("%d %d %d\n", data[0], data[1], data[2]);
srcNodeID = data[0];
dstNodeID = data[1];
msgType = data[2];

if(msgType == 10) //Last FinishMsg Was Received
{
break;
/*
msgFlagArray[data[0]] = 1;

int FinishFlag = 1;
for(int i=0; i < nprocs; i++)
if(i!=rank && msgFlagArray[i]==0) FinishFlag = 0;

if(FinishFlag) break;
else continue;
*/ }
}
}

void simplifyDistNodeGraph()
{
pthread_t ComputingThd, ServiceThd;
pthread_attr_t attr;
void *thdStatus;
pthread_attr_init(&attr );
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

pthread_create(&ComputingThd, &attr, computingFun, (void*) NULL);
pthread_create(&ServiceThd, &attr, serviceFun, (void*) NULL);

pthread_join(ComputingThd, &thdStatus);
pthread_join(ServiceThd, &thdStatus);

pthread_attr_destroy(&attr);
}

int main(int argc, char* argv[])
{
int rank;
MPI_Offset size;
int rc;
int nprocs;
MPI_File cFile;
MPI_Status status;

int provided, flag, claimed;
MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
if(provided != MPI_THREAD_MULTIPLE)
{
printf("MPI do not Support Multiple thread\n");
exit(0);
}

// MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD,&nprocs);

simplifyDistNodeGraph();

MPI_Finalize();
return 0;
}



上面这个程序 当所有ComputingThread执行完任务后(向ServiceThread发送指令,并接受数据),调用MPI_Gather收集所有的ComputingThread都执行完毕的信号1, 然后进程0的ComputingThread发送一个10的信号给所有的ServiceThread去关闭它们,同时所有的ComputingThread也关闭自己。
下图是线程通讯图例。


在这里,程序用的是gcc4.3, MPICH2_1.4.1p1, 网络是infiniband IPoIB. 请问当进程超过2048以后就会报MPI_Send/MPI_Recv出错呢? 如果需要修改的,大家有什么建议么?




...全文
358 3 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
donkeymeng 2012-06-07
  • 打赏
  • 举报
回复
谢谢 FelixHao, 首先关于MPI_Send使得系统缓冲溢出的问题,应该是阿贡国家实验室来保证这种情况不会发生,如果发生的话,我们需要把代码和出错信息发给阿贡实验室。当然当务之急是接受您的建议,使用MP_Ssend来代替MPI_Send执行我的代码,看看是否还会出错。

其次关于MPI_Send/Recv的 tag使用,这里使用Tag来标识通讯信道(CommandTunnel, DataTunnel, ServiceTunnel) 并管理线程间的数据收发。
1. 计算线程只能向CommandTunnel发送命令,只有服务线程能在CommandTunnel取得命令。
2. 服务线程能在ServiceTunnel里放回复消息,只有计算线程可以从serviceTunnel取得回复消息
3. 如果计算线程需要发送数据,那么计算线程只需要把数据消息放入DataTunnel, 服务线程可以到DataTunnel取得数据消息。

通过这3个通道来这样来实现消息收发和命令的协作。

您指定了目标线程和源线程的话,一般是会可靠的传达消息的,“如果本来应当进程0Send,进程1接受的,不知怎么就变成了两个都在发送或者都在接受了…… ” 这种情况如果你能捕捉到的话,可以发邮件给mpich-discuss@mcs.anl.gov 询问
FelixHao 2012-05-11
  • 打赏
  • 举报
回复
我正在处理很类似的问题,也是多线程,一个计算,一个控制,还有别的无关的线程。MPI_Recv和MPI_Send会抛出access violation的异常。
我说一下我觉得有可能出现的问题吧:
MPICH2中MPI_Send的实现是利用缓冲的,也就是说MPI_Send会在发送的内容拷贝到系统缓冲中之后立刻返回,并不关心内容是否实际上被发送出去。当你连续发送很多内容时(2048个?),有可能会使系统缓冲溢出。这时候,会报too many unexpected message的问题。解决方法是用MPI_Ssend替代MPI_Send,或者增加别的同步措施,比如每发送100次MPI_Barrier一下之类的。
我当时用VisualStudio调试我的代码的时候发现程序报错时实际上是因为语句执行顺序出错,比如本来应当进程0Send,进程1接受的,不知怎么就变成了两个都在发送或者都在接受了……
多线程中多多使用tag来帮助你在不同线程中区分消息的目的线程,我的习惯是给每一个线程分配一个tag,发送到一个线程的消息必须使用与这个线程对应的tag,同理,这个线程只应当接受标记为对应的tag的消息。不过这不是你这个问题的原因。
不指望能解决问题,但希望能有所启发
modyaj 2012-03-20
  • 打赏
  • 举报
回复
初学这个 看了一哈 没法帮你

567

社区成员

发帖
与我相关
我的任务
社区描述
英特尔® 边缘计算,聚焦于边缘计算、AI、IoT等领域,为开发者提供丰富的开发资源、创新技术、解决方案与行业活动。
社区管理员
  • 英特尔技术社区
  • shere_lin
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧